1 | | % (c) 2006-2024 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, |
2 | | % Heinrich Heine Universitaet Duesseldorf |
3 | | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) |
4 | | |
5 | | |
6 | | :- module(symmetry_marker,[compute_marker_for_state/2, |
7 | | type_allows_for_precise_marker/1, |
8 | | hash_model_checking_imprecise/2 |
9 | | %non_symmetric_type/1 |
10 | | ]). |
11 | | /* Created: 28/9/06 */ |
12 | | |
13 | | |
14 | | :- use_module(probsrc(module_information)). |
15 | | :- module_info(group,symmetry). |
16 | | :- module_info(description,'This module computes symmetry hash markers for B states (used for hash symmetry).'). |
17 | | |
18 | | :- use_module(probsrc(debug)). |
19 | | |
20 | | :- use_module(library(lists)). |
21 | | |
22 | | /* marker(Object, Type, ValueAsTerm) */ |
23 | | |
24 | | :- use_module(probsrc(b_global_sets),[is_unused_b_global_constant/2, |
25 | | b_global_deferred_set_with_card_gt1/1, b_global_set_with_potential_symmetry/1]). |
26 | | |
27 | | :- use_module(probsrc(error_manager)). |
28 | | |
29 | | type_allows_for_precise_marker(integer). |
30 | | type_allows_for_precise_marker(real). |
31 | | type_allows_for_precise_marker(string). |
32 | | type_allows_for_precise_marker(boolean). |
33 | | type_allows_for_precise_marker(set(global(_))) :- !. % ok, whether global set deferred or not |
34 | | type_allows_for_precise_marker(set(couple(X,Y))) :- !, |
35 | | (Y=global(_),non_symmetric_type(X) -> true |
36 | | % type_allows_for_precise_marker(Y) not ok; unless we are guaranteed to have a function |
37 | | ; X=global(_),non_symmetric_type(Y) -> true % see comment above |
38 | | ; non_symmetric_type(X), non_symmetric_type(Y) -> true |
39 | | ; print_fail(set(couple(X,Y)))). |
40 | | type_allows_for_precise_marker(set(X)) :- |
41 | | (non_symmetric_type(X) -> true |
42 | | ; print_fail(set(X))). |
43 | | type_allows_for_precise_marker(seq(X)) :- !, type_allows_for_precise_marker(set(couple(integer,X))). |
44 | | type_allows_for_precise_marker(global(_)). |
45 | | type_allows_for_precise_marker(couple(X,Y)) :- !,type_allows_for_precise_marker(X), |
46 | | type_allows_for_precise_marker(Y). |
47 | | type_allows_for_precise_marker(record(F)) :- !, fields_allows_for_precise_marker(F). |
48 | | % TODO: freetypes |
49 | | |
50 | | fields_allows_for_precise_marker([]). |
51 | | fields_allows_for_precise_marker([field(_Name,Type)|T]) :- |
52 | | type_allows_for_precise_marker(Type), |
53 | | fields_allows_for_precise_marker(T). |
54 | | |
55 | | :- use_module(probsrc(preferences),[get_preference/2]). |
56 | | hash_model_checking_imprecise(ID,BasicType) :- %print(check),nl, |
57 | | get_preference(symmetry_mode,hash), |
58 | | (b_get_machine_constants(TL) ; b_get_machine_variables(TL)), |
59 | | member(b(identifier(ID),BasicType,_),TL), |
60 | | \+ type_allows_for_precise_marker(BasicType). |
61 | | |
62 | | |
63 | | %:- use_module(probsrc(translate),[pretty_type/2]). |
64 | | print_fail(_T) :- |
65 | | %print('*** type may lead to imprecise hash marker:'), |
66 | | %translate:pretty_type(T,S),print(S),nl, |
67 | | fail. |
68 | | % a type which does not contain any deferred set elements |
69 | | non_symmetric_type(integer) :- !. |
70 | | non_symmetric_type(boolean) :- !. |
71 | | non_symmetric_type(real) :- !. |
72 | | non_symmetric_type(string) :- !. |
73 | | non_symmetric_type(set(X)) :- !, non_symmetric_type(X). |
74 | | non_symmetric_type(couple(X,Y)) :- !,non_symmetric_type(X), non_symmetric_type(Y). |
75 | ? | non_symmetric_type(global(X)) :- !, \+ b_global_set_with_potential_symmetry(X). |
76 | | non_symmetric_type(seq(X)) :- !, non_symmetric_type(X). |
77 | | non_symmetric_type(record(F)) :- !, non_symmetric_fields(F). |
78 | | non_symmetric_type(freetype(_)) :- !. |
79 | | non_symmetric_type(any) :- !. |
80 | | non_symmetric_type(constant(_)) :- !. |
81 | | non_symmetric_type(X) :- add_error_fail(non_symmetric_type,'Unknown type: ',X). |
82 | | |
83 | | non_symmetric_fields([]). |
84 | | non_symmetric_fields([field(_Name,Type)|T]) :- non_symmetric_type(Type), |
85 | | non_symmetric_fields(T). |
86 | | |
87 | | /* first a predicate to count the occurrences of anonymous set elements */ |
88 | | |
89 | | /* possible improvement: count nr of occurences for each variable */ |
90 | | |
91 | | :- use_module(probsrc(bmachine),[b_get_machine_constants/1, b_get_machine_variables/1]). |
92 | | :- volatile non_symmetric_var/2. |
93 | | :- dynamic non_symmetric_var/2. |
94 | | precompile_marker_typing_info :- |
95 | | retractall(non_symmetric_var(_,_)), |
96 | | bmachine:b_get_machine_variables(TypedVarList), |
97 | | bmachine:b_get_machine_constants(TypedCstList), |
98 | | append(TypedCstList,TypedVarList,List), |
99 | | analyse_typed_varlist(List). |
100 | | |
101 | | analyse_typed_varlist([]). |
102 | | analyse_typed_varlist([b(identifier(ID),Type,_)|T]) :- |
103 | | (non_symmetric_type(Type) |
104 | | -> assertz(non_symmetric_var(ID,Type)) |
105 | | %% ,print(non_sym(ID,Type)),nl |
106 | | ; true), |
107 | | analyse_typed_varlist(T). |
108 | | |
109 | | :- use_module(probsrc(eventhandling),[register_event_listener/3]). |
110 | | :- register_event_listener(specification_initialised,precompile_marker_typing_info, |
111 | | 'Detect non-symmetric types for variables and constants.'). |
112 | | |
113 | | %:- dynamic count/4. |
114 | | |
115 | | |
116 | | count_state(State) :- empty_avl(E), |
117 | | %nl,translate:print_bstate(State),nl, |
118 | | count_env(State,E,Out), |
119 | | %portray_avl(Out),nl, |
120 | | compute_deferred_set_el_markers(Out). |
121 | | |
122 | | count_env([],I,O) :- !, O=I. |
123 | | count_env([bind(Var,Val)|T],In,Out) :- !, |
124 | | (non_symmetric_var(Var,_) -> In=I1 |
125 | | ; %print(counting(Var)),nl, |
126 | | count_obj(Val,Var,In,I1)), |
127 | | count_env(T,I1,Out). |
128 | | count_env(E,I,O) :- add_error(symmetry_marker,'Illegal env: ',E), O=I. |
129 | | |
130 | | :- use_module(library(avl)). |
131 | | /* IDEA: instead of just storing variable Var, store entire path to |
132 | | occurrence of fd(Nr,T) */ |
133 | | count_obj(fd(Nr,T),PathToObject,In,Out) :- !, %print(fd(Nr,T)), |
134 | ? | ((b_global_deferred_set_with_card_gt1(T) ; |
135 | | is_unused_b_global_constant(T,Nr) /* TO DO: only makes sense if more than one unused global constant */ |
136 | | ) |
137 | | -> %add_count(PathToObject,Nr,T,In,Out) |
138 | | add_avl_count(In,usage_count(Nr,T,PathToObject),Out) |
139 | | ; Out=In |
140 | | ). |
141 | | count_obj((X,Y),PathToObject,In,Out) :- !, count_pair(X,Y,PathToObject,In,Out). |
142 | | count_obj([X|Y],PathToObject,In,Out) :- !, |
143 | | (could_contain_deferred_set_elements(X) |
144 | | -> count_obj_list([X|Y],PathToObject,In,Out) /* only count set if there are deferred set elements inside */ |
145 | | ; Out=In |
146 | | ). |
147 | | count_obj(avl_set(A),PathToObject,In,Out) :- !, |
148 | | (avl_could_contain_deferred_set_element(A) |
149 | | -> count_avl(A,el(PathToObject),In,Out) |
150 | | ; Out=In |
151 | | ). |
152 | | count_obj(rec(Fields),PathToObject,In,Out) :- !, |
153 | | count_obj_field_list(Fields,PathToObject,In,Out). |
154 | | count_obj(freeval(ID,Case,Val),freeval(ID,Case,PathToObject),In,Out) :- !, |
155 | | count_obj(Val,PathToObject,In,Out). |
156 | | %count_obj([],_,O,O). |
157 | | count_obj(_,_,O,O). |
158 | | % no need to have base case for empty avl; as empty set represented by [] |
159 | | |
160 | | |
161 | | count_avl(empty,_PathToObject) --> []. |
162 | | count_avl(node(Key,_True,_,L,R),PathToObject) --> |
163 | | count_avl(L,PathToObject), count_obj(Key,PathToObject), |
164 | | count_avl(R,PathToObject). |
165 | | |
166 | | count_pair(X,Y,PathToObject,In,Out) :- not_symmetric(Y),!, |
167 | | count_obj(X,mapped_to(PathToObject,Y),In,Out). |
168 | | count_pair(X,Y,PathToObject,In,Out) :- not_symmetric(X),!, |
169 | | count_obj(Y,mapped_from(X,PathToObject),In,Out). |
170 | | count_pair(X,X,PathToObject,In,Out) :- !, /* is this correct ?? |
171 | | should we only do it for simple X, what about sets: should |
172 | | work if normalised ?? */ |
173 | | count_obj(X,leftright(PathToObject),In,Out). |
174 | | count_pair(X,Y,PathToObject,In,Out) :- !, |
175 | | count_obj(X,left(PathToObject),In,I1), |
176 | | count_obj(Y,right(PathToObject),I1,Out). |
177 | | |
178 | | |
179 | | could_contain_deferred_set_elements([]). |
180 | | could_contain_deferred_set_elements([H|_]) :- could_contain_deferred_set_elements(H). |
181 | | could_contain_deferred_set_elements(fd(_Nr,_T)). |
182 | | %b_global_deferred_set_with_card_gt1(T) ; b_global_sets:is_unused_b_global_constant(T,Nr). |
183 | | could_contain_deferred_set_elements((A,B)) :- |
184 | | (could_contain_deferred_set_elements(A) -> true ; could_contain_deferred_set_elements(B)). |
185 | | could_contain_deferred_set_elements(avl_set(A)) :- avl_could_contain_deferred_set_element(A). |
186 | | could_contain_deferred_set_elements(rec(Fields)) :- |
187 | | member(field(_,A),Fields), could_contain_deferred_set_elements(A),!. |
188 | | |
189 | | avl_could_contain_deferred_set_element(node(X,_,_,_L,_R)) :- /* first underscore should be true */ |
190 | | could_contain_deferred_set_elements(X). |
191 | | %an_avl_element(node(X,_,_,_L,_R),X). /* first underscore should be true */ |
192 | | |
193 | | count_obj_list([],_,O,O). |
194 | | count_obj_list([X|Y],PathToObject,In,Out) :- |
195 | | count_obj(X,el(PathToObject),In,I1), |
196 | | count_obj(Y,PathToObject,I1,Out). |
197 | | |
198 | | count_obj_field_list([],_,O,O). |
199 | | count_obj_field_list([field(FX,VX)|T],PathToObject,In,Out) :- |
200 | | count_obj(VX,field(FX,PathToObject),In,I1), |
201 | | count_obj_field_list(T,PathToObject,I1,Out). |
202 | | |
203 | | /* not_symmetric: check if object has symmetric permutations */ |
204 | | not_symmetric([]). |
205 | | not_symmetric((X,Y)) :- not_symmetric(X), not_symmetric(Y). |
206 | | not_symmetric(pred_false /* bool_false */). |
207 | | not_symmetric(pred_true /* bool_true */). |
208 | | not_symmetric(string(_)). |
209 | | not_symmetric(fd(Nr,T)) :- |
210 | | \+ b_global_deferred_set_with_card_gt1(T), |
211 | | \+ is_unused_b_global_constant(T,Nr). /* TO DO: only makes sense if more than one unused global constant */ |
212 | | not_symmetric(int(_)). |
213 | | not_symmetric(term(_)). |
214 | | not_symmetric(freeval(_,_,Val)) :- not_symmetric(Val). |
215 | | not_symmetric(rec(Fields)) :- \+ (member(field(_,X),Fields), \+ not_symmetric(X)). |
216 | | /* add same for sets ?? */ |
217 | | |
218 | | |
219 | | % add_avl_count(usage_count(Nr,T,PathToObject),In,Out) |
220 | | add_avl_count(AVL,Key,NewAVL) :- %print(add_count(Key)),nl, |
221 | | (avl_fetch(Key,AVL,OldCount) |
222 | | -> NewCount is OldCount+1, |
223 | | avl_change(Key,AVL,_,NewAVL,NewCount) |
224 | | ; avl_store(Key,AVL,1,NewAVL) |
225 | | ). %, print(ok(NewCount)),nl. |
226 | | |
227 | | |
228 | | /* |
229 | | add_count(Var,Nr,T) :- |
230 | | (retract(count(Nr,T,Var,C1)) |
231 | | -> (C is C1+1, assertz(count(Nr,T,Var,C))) |
232 | | ; assertz(count(Nr,T,Var,1)) |
233 | | ). */ |
234 | | |
235 | | :- volatile deferred_set_el_marker/3. |
236 | | :- dynamic deferred_set_el_marker/3. |
237 | | |
238 | | /* compute individual markers for deferred set elements by hashing |
239 | | classical path information using sha */ |
240 | | |
241 | | /* |
242 | | compute_deferred_set_el_markers(CountAVL) :- |
243 | | retractall(deferred_set_el_marker(_,_,_)), |
244 | | avl_generate_el_markers(CountAVL,'$DUMMY',-1,[],OutType,OutNr,OutCount), |
245 | | %% print(last_marker(OutType,OutNr,OutCount)),nl, %% |
246 | | assert_def_marker(OutType,OutNr,OutCount). |
247 | | |
248 | | avl_generate_el_markers(empty,CurType,CurElNr,CurCount,CurType,CurElNr,CurCount). |
249 | | avl_generate_el_markers(node(usage_count(Nr,T,Path),Count,_,L,R),CurType,CurElNr,CurCount, |
250 | | OutT,OutNr,OutCount) :- |
251 | | avl_generate_el_markers(L,CurType,CurElNr,CurCount,T1,N1,C1), |
252 | | ((N1=Nr,T1=T) % we are still treating the same deferred set element fd(T,Nr) |
253 | | -> C2=[count(Path,Count)|C1] % add cur path to list of paths for fd(T,Nr) |
254 | | ; assert_def_marker(T1,N1,C1), % assert cur paths for fd(T1,N1) |
255 | | % We could use instead: avl_store(fd(T1,N1),AVL,el(T1,C1),NewAVL) |
256 | | %print(marker(T1,N1,C1)),nl, %% |
257 | | C2 = [count(Path,Count)] % start fresh; collecting paths for fd(T,Nr) |
258 | | ), avl_generate_el_markers(R,T,Nr,C2,OutT,OutNr,OutCount). |
259 | | |
260 | | :- use_module(extension('probhash/probhash'),[raw_sha_hash/2]). |
261 | | assert_def_marker(T1,N1,C1) :- probhash:raw_sha_hash(el(T1,C1),MHash), |
262 | | assertz(deferred_set_el_marker(T1,N1,MHash)). |
263 | | */ |
264 | | |
265 | | /* |
266 | | an attempt at not storing paths but just sort the fd-elements according to path |
267 | | information and assign them a number: without adding id_couple below in marker/3 we get collisions, e.g, for |
268 | | ./probcli examples/B/SymmetryReduction/PhilRing.mch -mc 1000 -p DEFAULT_SETSIZE 3 -p SYMMETRY_MODE hash -cc 13 47 |
269 | | */ |
270 | | |
271 | | compute_deferred_set_el_markers(CountAVL) :- |
272 | | avl_to_list(CountAVL,AList), |
273 | | %print(AList),nl, |
274 | | merge_paths(AList,BList), |
275 | | sort(BList,SBList), |
276 | | %print(merged(SBList)),nl, |
277 | | retractall(deferred_set_el_marker(_,_,_)), |
278 | | assert_markers(SBList,0),!. |
279 | | |
280 | | % merge all the information for same deferred set elements (Nr,Type) |
281 | | merge_paths([],[]). |
282 | | merge_paths([usage_count(Nr,Type,Path)-Count|Tail],Res) :- |
283 | | merge_paths(Tail,Nr,Type,[count(Path,Count)],Res). |
284 | | |
285 | | merge_paths([],Nr,Type,MarkerPaths,[marker(Type,MarkerPaths,Nr)]). % :- print(marker(Type,MarkerPaths,Nr)),nl. |
286 | | merge_paths([usage_count(Nr,Type,Path)-Count|Tail],Nr,Type,M,Res) :- !, |
287 | | merge_paths(Tail,Nr,Type,[count(Path,Count)|M],Res). |
288 | | merge_paths([usage_count(Nr,Type,Path)-Count|Tail],Nr2,T2,M,[marker(T2,M,Nr2)|Res]) :- |
289 | | % print(marker(T2,Nr2,M)),nl, |
290 | | merge_paths(Tail,Nr,Type,[count(Path,Count)],Res). |
291 | | |
292 | | assert_markers([],_). |
293 | | assert_markers([marker(Type,Paths,Nr)|T],ID) :- |
294 | | get_same_markers(T,Type,Paths,Same,TT,NrSame), % get all other elements with same Paths information |
295 | | ID1 is ID+1, |
296 | | (NrSame=0 -> assertz(deferred_set_el_marker(Type,Nr,fdunique(ID1,Type))) |
297 | | ; assert_same_markers([Nr|Same],Type,ID1,NrSame)), |
298 | | assert_markers(TT,ID1). |
299 | | |
300 | | get_same_markers([marker(Type,Paths,Nr)|T],Type,Paths,[Nr|SM],TT,ResNr) :- !, |
301 | | get_same_markers(T,Type,Paths,SM,TT,SNr), ResNr is SNr+1. |
302 | | get_same_markers(T,_,_,[],T,0). |
303 | | |
304 | | |
305 | | assert_same_markers([],_,_,_). |
306 | | assert_same_markers([Nr|T],Type,ID,NrSame) :- |
307 | | assertz(deferred_set_el_marker(Type,Nr,fdsame(ID,Type,NrSame))), |
308 | | assert_same_markers(T,Type,ID,NrSame). |
309 | | |
310 | | |
311 | | /* */ |
312 | | |
313 | | |
314 | | % ------------------------------------------------------- |
315 | | |
316 | | |
317 | | /* marker(+ProBOBject, -TypeOfObject, -HashTerm) */ |
318 | | |
319 | | |
320 | | :- use_module(probsrc(custom_explicit_sets)). |
321 | | :- use_module(probsrc(kernel_reals),[is_real/2]). |
322 | | :- use_module(probsrc(kernel_freetypes),[freetype_case_db/3]). |
323 | | |
324 | | /* missing: closure, records,... */ |
325 | | marker(closure(P,T,B),set(any),closure(P,T,B)). |
326 | | marker(global_set(GS),set(Type),Local) :- |
327 | | marker_explicit_set(global_set(GS),set(Type),Local). |
328 | | marker(avl_set(S),set(Type),SLocal) :- % marker_explicit_set(avl_set(S),set(Type),Val,Local). |
329 | | (avl_marker(S, Type,Local) -> true ; print(failed_avl_marker(S)),nl,fail), |
330 | | sort_markers(Local,SLocal). |
331 | | marker(closure_x(P,T,B,E),set(Type),Local) :- |
332 | | marker_explicit_set(closure_x(P,T,B,E),set(Type),Local). |
333 | | marker(int(N), integer, N). % int(N) |
334 | | marker(string(S), string, S). % string(S)). |
335 | | marker(term(F), real, R) :- is_real(term(F),R). |
336 | | marker(fd(Nr,T), global(T), Term) :- |
337 | | (deferred_set_el_marker(T,Nr,Term) |
338 | | -> true |
339 | | ; (b_global_deferred_set_with_card_gt1(T) |
340 | | -> print(not_counted(Nr,T)),nl ; true), |
341 | | Term=fd(Nr,T) /*should not happen for deferred sets */ |
342 | | ). |
343 | | marker(pred_false /* bool_false */, boolean, pred_false). |
344 | | marker(pred_true /* bool_true */, boolean, pred_true). |
345 | | marker(freeval(ID,Case,V),_Type,freeval_marker(Case,VM)) :- |
346 | | freetype_case_db(Case,ID,CaseType), |
347 | | marker(V,CaseType,VM). |
348 | | marker((X,Y), couple(T1,T2), Mark) :- |
349 | | (X==Y -> Mark = id_couple(L1), marker(X,T1,L1) % added 7/9/2011 by leuschel |
350 | | ; Mark = couple(L1,L2), marker(X,T1,L1),marker(Y,T2,L2)). |
351 | | marker([], set(_), []). |
352 | | marker([H|T], set(Type), Local) :- |
353 | | l_marker([H|T],Type,LL), |
354 | | sort_markers(LL,Local). |
355 | | marker(rec(Fields), record(FTypes), Local) :- |
356 | | fields_marker(Fields,FTypes,Local). |
357 | | %marker(A,T,_) :- write(uncovered_marker(A,T)),nl,trace,fail. |
358 | | |
359 | | marker_explicit_set(ES,set(Type),Local) :- |
360 | | expand_custom_set_to_list_now(ES,Res), |
361 | | l_marker(Res,Type,LL), |
362 | | sort_markers(LL,Local). |
363 | | |
364 | | l_marker([], _Type, []). |
365 | | l_marker([H|T], Type, [LH|LT]) :- |
366 | | marker(H,Type,LH), |
367 | | l_marker(T,Type,LT). |
368 | | |
369 | | fields_marker([], _Type, []). |
370 | | fields_marker([field(Name,H)|T], [field(Name,Type1)|TR], [LH|LT]) :- % field name not required in marker |
371 | | marker(H,Type1,LH), |
372 | | fields_marker(T,TR,LT). |
373 | | |
374 | | avl_marker(Avl, Type,Local) :- avl_domain(Avl,List), |
375 | | l_marker(List,Type,Local). |
376 | | |
377 | | |
378 | | |
379 | | /* example queries: |
380 | | use_module(symsrc(symmetry_marker)), |
381 | | symmetry_marker:compute_marker_for_state([bind(tr,[(fd(1,'Session'),fd(1,'Session')),(fd(1,'Session'),fd(2,'Session'))]), |
382 | | bind(inv,[fd(1,'Session')]),bind(i,fd(1,'Session')), |
383 | | bind(reach,[fd(1,'Session'),fd(2,'Session')]),bind(rac,[fd(1,'Session')])],M). |
384 | | |
385 | | symmetry_marker:nodes_in_graph([(fd(1,'Session'),fd(1,'Session')),(fd(1,'Session'),fd(2,'Session'))],N). |
386 | | |
387 | | use_module(symmetry_marker),symmetry_marker:cm. |
388 | | |
389 | | use_module(symsrc(symmetry_marker)), |
390 | | symmetry_marker:count_state([bind(tr,[(fd(1,'Session'),fd(1,'Session')),(fd(1,'Session'),fd(2,'Session'))]), |
391 | | bind(inv,[fd(1,'Session')]),bind(i,fd(1,'Session')), |
392 | | bind(reach,[fd(1,'Session'),fd(2,'Session')]),bind(rac,[fd(1,'Session')])]), |
393 | | symmetry_marker:count(X,Y,Z). |
394 | | */ |
395 | | |
396 | | |
397 | | :- use_module(library(samsort)). |
398 | | |
399 | | sort_markers(X,SX) :- samsort(X,SX). % sort without duplicate removal |
400 | | |
401 | | |
402 | | |
403 | | :- use_module(probsrc(specfile),[expand_const_and_vars_to_full_store/2]). |
404 | | |
405 | | :- use_module(probsrc(self_check)). |
406 | | :- assert_must_succeed((symmetry_marker:compute_marker_for_state([bind(x,fd(1,'Name')),bind(y,fd(2,'Name'))],R1), |
407 | | symmetry_marker:compute_marker_for_state([bind(x,fd(2,'Name')),bind(y,fd(1,'Name'))],R2),R1==R2)). |
408 | | |
409 | | compute_marker_for_state(State,Marker) :- |
410 | | (State = concrete_constants(BState) |
411 | | -> Marker = concrete_constants(BMarker) |
412 | | ; (State = csp_and_b(CSPState,BState) |
413 | | -> Marker = csp_and_b(CSPState,BMarker) |
414 | | ; (State=[] ; State = [_|_] ; State = const_and_vars(_,_) ), |
415 | | State=BState, Marker=BMarker |
416 | | ) |
417 | | ), |
418 | | expand_const_and_vars_to_full_store(BState,FullBState), |
419 | | count_state(FullBState), /* first count the number of occurrences |
420 | | of every symmetric element in the State; this number will |
421 | | be used as the marker for that element */ |
422 | | marker_for_state(FullBState,BMarker). |
423 | | % ,probhash:raw_sha_hash(BMarker0,BMarker). % , print(marker_for_state(FullBState,BMarker)),nl,nl. |
424 | | |
425 | | /* compute a marker for a given state */ |
426 | | marker_for_state([],[]). |
427 | | marker_for_state([bind(Var,Val)|T],[M|TM]) :- |
428 | | (non_symmetric_var(Var,_) |
429 | | -> TermMarker=Val |
430 | | ; marker(Val, _Type,TermMarker)), |
431 | | M=mark(Var,TermMarker), |
432 | | marker_for_state(T,TM). |
433 | | |
434 | | |
435 | | % TESTING CODE |
436 | | |
437 | | /* |
438 | | :- dynamic marker/2. |
439 | | % symmetry_marker:cm. |
440 | | % symmetry_marker:marker(10,M1), symmetry_marker:marker(18,M2), M1=M2. |
441 | | |
442 | | :- public cm/0. |
443 | | cm :- |
444 | | print('Computing markers for state space'),nl, |
445 | | retractall(marker(_,_)), |
446 | | cms(ID, M), |
447 | | assertz(marker(ID,M)), |
448 | | fail. |
449 | | cm :- |
450 | | marker(ID,Marker), |
451 | | marker(ID2,Marker), ID2 > ID, |
452 | | print(same_marker(ID,ID2)),nl, |
453 | | fail. |
454 | | cm :- print('Finished'),nl. |
455 | | |
456 | | :- use_module(probsrc(state_space),[visited_expression/2]). |
457 | | cms(ID, M) :- |
458 | | state_space:visited_expression(ID,State), |
459 | | compute_marker_for_state(State,M), |
460 | | print(marker(ID,State,M)),nl. |
461 | | |
462 | | |
463 | | :- public test_sym/0. |
464 | | test_sym :- state_space:visited_expression(ID,State), |
465 | | print(ID), print(' : '), |
466 | | sym_mark_for_state(State). |
467 | | |
468 | | sym_mark_for_state(State) :-print(State),nl, |
469 | | member(bind(Var,Val),State), |
470 | | print(Var), print(' = '), |
471 | | marker(Val, T,L), |
472 | | print(marker(Val,T,L)), |
473 | | print(' '), |
474 | | nl, |
475 | | fail. |
476 | | sym_mark_for_state(_) :- nl. |
477 | | */ |