1 % (c) 2009-2019 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(b_compiler,[b_compile/6, b_optimize/6]).
7
8 :- use_module(library(lists)).
9
10 :- use_module(self_check).
11 :- use_module(bsyntaxtree).
12 :- use_module(error_manager).
13 :- use_module(btypechecker,[fasttype/2]).
14 :- use_module(b_interpreter).
15 :- use_module(custom_explicit_sets).
16 %:- use_module(bmachine,[b_operation_reads_output_variables/3]).
17
18 :- use_module(module_information,[module_info/2]).
19 :- module_info(group,interpreter).
20 :- module_info(description,'This module compiles set comprehensions into closures; making them independent of the state of the B machine.').
21
22 /* compile boolean expression into a closure where the local state and the global
23 state has been incorporated, but any parameter is left in the closure */
24
25 :- public test_bexpr/3, test_bexpr2/3.
26 test_bexpr(Expr,[bind(cc,int(1)),bind(nn,int(2))], [bind(db,[(int(1),int(2))])]) :-
27 fasttype( +conjunct( +conjunct( +member( global('Name')<<identifier(nn), +identifier('Name')),
28 +member( global('Code')<<identifier(cc), +identifier('Code'))),
29 +not_member( global('Name')<<identifier(nn),
30 +domain(set(couple(global('Name'),global('Code')))<<identifier(db)))), Expr).
31
32 test_bexpr2(Expr,[],[]) :-
33 fasttype( +implication( +equal( seq(any)<<identifier(ss), +empty_sequence),
34 +equal( set(any)<<identifier(res), +empty_set)), Expr).
35
36
37 % difference with b_compile: the states LS, S will not be thrown away by the interpreter
38 % thus: we do not have to compile all accesses, in particular lazy lookups !
39 %b_optimize(TExpr,Parameters,_LS,_S,NTExpr,_WF) :- TExpr=b(_,_,Infos), member(already_optimized,Infos),
40 % !, NTExpr=TExpr.
41 b_optimize(TExpr,Parameters,LS,S,NTExpr,WF) :- %print('OPTIMIZE: '),translate:print_bexpr(TExpr),nl, trace,
42 append(LS,[bind('$do_not_force_lazy_lookups',pred_true)],NewLS),
43 b_compile(TExpr,Parameters,NewLS,S,NTExpr,WF).
44 %bsyntaxtree:add_texpr_info_if_new(NTExpr,already_optimized,ResTExpr).
45
46 b_compile(TExpr,Parameters,NewLS,S,NTExpr) :-
47 b_compile(TExpr,Parameters,NewLS,S,NTExpr,no_wf_available). % for unit tests
48
49 :- assert_must_succeed(( b_compiler:test_bexpr(E,L,S),
50 b_compiler:b_compile(E,[nn],L,S,_R) )).
51 :- assert_must_succeed(( b_compiler:test_bexpr2(E,L,S),
52 b_compiler:b_compile(E,[ss,res],L,S,_R) )).
53
54 %:- assert_pre(b_compiler:b_compile_boolean_expression(E,Parameters,LS,S,_),
55 % (type_check(E,boolean_expression),type_check(Parameters,list(variable_id)),
56 % type_check(LS,store),type_check(S,store))).
57 %:- assert_post(b_compiler:b_compile_boolean_expression(_,_,_,_,E), type_check(E,boolean_expression)).
58
59 /* probably not worthwhile:
60 b_compile(TExpr,Parameters,LS,S,NTExpr) :- get_texpr_info(TExpr,Info),
61 (memberchk(compiled(Parameters),Info) -> NTExpr = TExpr ,print(already_compiled(Parameters)),nl, translate:print_bexpr(TExpr),nl
62 ; b_compile0(TExpr,Parameters,LS,S,b(E,T,I)), translate:print(compiling(Parameters)),nl, translate:print_bexpr(TExpr),nl,
63 NTExpr = b(E,T,[compiled(Parameters)|I])).
64 */
65
66 b_compile(TExpr,Parameters,LS,S,NTExpr,WF) :- check_is_id_list(Parameters,Parameters1),
67 % print('compile : '),translate:print_bexpr(TExpr),nl, statistics(runtime,[Start,_]),%%
68 if(b_compile1(TExpr,Parameters1,LS,S,NTExpr0,eval,_FullyKnown,WF),
69 copy_pos_infos(TExpr,NTExpr0,NTExpr), % ensure position info is not deleted if full expression compiled away, see PROB-412
70 (add_internal_error('Compilation failed: ',b_compile(TExpr,Parameters,LS,S,NTExpr,WF)),
71 %b_compile1(TExpr,Parameters1,LS,S,NTExpr0,eval,_FullyKnown,WF),
72 NTExpr = TExpr)
73 ). %, check_infos(TExpr,NTExpr).
74 %, print('compiled: '), translate:print_bexpr(NTExpr), print(' '),statistics(runtime,[Stop,_]), T is Stop-Start, print(T), print(' ms '),nl, bsyntaxtree:check_ast(NTExpr). % , print(NTExpr),nl. check_ast
75
76 /*
77 check_infos(Old,New) :- bsyntaxtree:get_texpr_info(Old,IO),
78 bsyntaxtree:get_texpr_info(New,IN),
79 member(X,IO), \+ member(X,IN),
80 bsyntaxtree:important_info(X),
81 print(check_infos(Old,New)),nl,
82 print('Not copied: '), print(X),fail.
83 check_infos(_,_). */
84
85 :- use_module(bsyntaxtree,[always_well_defined/1]).
86 :- use_module(translate,[translate_bexpression_with_limit/2]).
87 %:- use_module(hit_profiler,[add_profile_hit/1]).
88 b_compile1(TExpr,Parameters,LS,S,ResultTExpr,Eval,FullyKnown1,WF) :-
89 TExpr = b(Expr,Type,Infos),
90 NTExpr = b(NewUntypedExpr,Type,NewInfos),
91 %remove_bt(TExpr,Expr,NewUntypedExpr,NTExpr), % remove top-level Type Information
92 %hit_profiler:add_profile_hit(Expr),
93 b_compile1_infos(Expr,Infos,Parameters,LS,S,NewUntypedExpr,NewInfos,Eval,FullyKnown,WF),
94 % print(' compiled : '),translate:print_bexpr_or_subst(NTExpr),nl,
95 % print(res(FullyKnown,Eval,NTExpr)),nl,
96 (FullyKnown=true, evaluate_this(Eval,NewUntypedExpr,Type,NewInfos)
97 -> % print('eval : '),translate:print_bexpr(NTExpr),nl, %
98 (nonvar(NewUntypedExpr),
99 b_interpreter:b_compute_expression_nowf(NTExpr,LS,S,ResultValue) % if( would be more prudent !?
100 -> %print(result(ResultValue)),nl,
101 %remove_bt(TExpr,Expr,value(ResultValue),ResultTExpr)
102 get_texpr_type(TExpr,TT),ResultTExpr = b(value(ResultValue),TT,[]),
103 FullyKnown1 = FullyKnown
104 %, print(compiled_value(ResultTExpr)),nl
105 ; translate_bexpression_with_limit(NTExpr,TTS),
106 add_internal_error('Undefined Value: ',b_compile1(TTS,Parameters,LS,S,_,_,_,WF)),
107 %trace, b_interpreter:b_compute_expression_nowf(NTExpr,LS,S,ResultValue),
108 ResultTExpr=NTExpr, FullyKnown1=false
109 )
110 ; % ((FullyKnown=true, NTExpr\=b(value(_),_,_)) -> format('not eval: ~w (~w)~n',[NTExpr,Eval]) ; true),
111 ResultTExpr=NTExpr,
112 (ResultTExpr = b(value(_),_,_) -> FullyKnown1=FullyKnown ; FullyKnown1=false)
113 ).
114
115
116 :- use_module(bsyntaxtree,[create_exists_or_let_predicate/3]).
117 b_compile1_infos(exists(ExistsPara,Pred),OldInfos,Parameters,LS,S,NExpr,NewInfos,Eval,FullyKnown,WF) :- !,
118 FullyKnown=false, % predicates never automatically evaluated in b_compile1
119 get_texpr_ids(ExistsPara,AtomicIds),
120 append(Parameters,AtomicIds,NParameters),
121 b_compile1(Pred,NParameters,LS,S,NPred,Eval,_FullyKnown1,WF),
122 (is_falsity(NPred) -> NExpr = falsity, NewInfos = OldInfos
123 ; is_truth(NPred) -> NExpr = truth, NewInfos = OldInfos
124 ; create_exists_or_let_predicate(ExistsPara,NPred,b(NExpr,pred,NI)),
125 %print('COMPILED EXISTS: '), translate:print_bexpr(b(NExpr,pred,NI)),nl,
126 ? (delete(OldInfos,used_ids(_),I1),
127 ? member(used_ids(NewUsedIds),NI) -> NewInfos = [used_ids(NewUsedIds)|I1]
128 ; %nl,print(missing_used_ids(OldInfos,NI)),nl, % can happen when we construt a let_predicate above
129 update_infos(NExpr,OldInfos,Parameters,NewInfos))
130 ).
131 b_compile1_infos(identifier(Id),OldInfos,Parameters,LS,S,NExpr,NewInfos,Eval,FullyKnown,WF) :- !,
132 ( memberchk(Id,Parameters) ->
133 NExpr = identifier(Id), FullyKnown=false, NewInfos = OldInfos
134 ; Id=op(_) ->
135 NExpr = identifier(Id), FullyKnown=false, NewInfos = OldInfos
136 ; b_interpreter:lookup_value_in_store_and_global_sets(Id,LS,S,Value) ->
137 NExpr = value(Value), (known_value(Value) -> FullyKnown=true ; FullyKnown=false),
138 NewInfos = [was_identifier(Id)|OldInfos]
139 % TO DO: store in info field the identifier
140 ; add_internal_error('Compilation of identifier failed: ',
141 b_compile2(identifier(Id),Parameters,LS,S,NExpr,Eval,FullyKnown,WF)),
142 NExpr = identifier(Id), FullyKnown=false, NewInfos = OldInfos
143 ).
144 b_compile1_infos(Expr,OldInfos,_Parameters,_LS,_S,NewUntypedExpr,NewInfos,_Eval,FullyKnown,_WF) :-
145 b_ast_cleanup:is_integer_set(Expr,_Set),!,
146 NewUntypedExpr=Expr, NewInfos=OldInfos,FullyKnown=true.
147 b_compile1_infos(operation_call_in_expr(Operation,OpCallParas),OldInfos,Parameters,LS,S,
148 Compiled,NewInfos,Eval,FullyKnown,WF) :- !,
149 def_get_texpr_id(Operation,op(OperationName)),
150 FullyKnown = false,
151 b_compile_l(OpCallParas,Parameters,LS,S,OpCallParaValues,Eval,_,WF),
152 b_get_operation_normalized_read_write_info(OperationName,Read,Modified),
153 exclude(operation_identifier,Read,ReadVars), % Read also contains operations; TO DO: check if this is ok in other places of source code of ProB; see test 1957
154 (Modified=[] -> true ; add_error(b_compiler,'Calling operation that modifies state in expression:',OperationName)),
155 % print(compile_call_op(OperationName,ReadVars,Modified,OpCallParaValues)),nl,
156 (ReadVars=[]
157 -> Compiled = operation_call_in_expr(Operation,OpCallParaValues),
158 NewInfos = OldInfos
159 ; maplist(create_value_for_read_variable(LS,S),ReadVars,TRead,TValues),
160 NewInfos = [generated_by_b_compiler],
161 Compiled = let_expression_global(TRead,TValues,
162 b(operation_call_in_expr(Operation,OpCallParaValues),any,OldInfos))
163 ).
164 b_compile1_infos(Expr,OldInfos,Parameters,LS,S,NewUntypedExpr,NewInfos,Eval,FullyKnown,WF) :-
165 b_compile2(Expr,Parameters,LS,S,NewUntypedExpr,Eval,FullyKnown,WF),
166 update_infos(NewUntypedExpr,OldInfos,Parameters,NewInfos).
167
168 :- use_module(bmachine,[b_get_operation_normalized_read_write_info/3]).
169
170 operation_identifier(op(_)).
171 create_value_for_read_variable(LS,S,Variable,TVariable,TValue) :-
172 b_interpreter:lookup_value_in_store_and_global_sets(Variable,LS,S,Value),!, % TO DO: try and find type?
173 TVariable = b(identifier(Variable),any,[]),
174 TValue = b(value(Value),any,[]).
175 create_value_for_read_variable(_LS,_S,Variable,TVariable,b(value(term(undefined)),any,[])) :-
176 TVariable = b(identifier(Variable),any,[]),
177 add_internal_error('Cannot find variable (read) while compiling operation:',Variable),fail.
178
179 :- use_module(library(ordsets)).
180 update_infos(forall(EParas,LHS,RHS),Infos,Parameters,NewInfos) :-
181 % forall also has used_ids field as it may call exists in negative context
182 conjunct_predicates([LHS,RHS],Cond),
183 update_infos_aux(EParas,Cond,Infos,Parameters,NewInfos),!.
184 update_infos(exists(EParas,Cond),Infos,Parameters,NewInfos) :- % we create_exists_or_let_predicate above, but other transformations may generate an exists below:
185 update_infos_aux(EParas,Cond,Infos,Parameters,NewInfos),!.
186 update_infos(BOP,Infos,_,NewInfos) :- bsyntaxtree:syntaxelement(BOP, [A,B],[], [], [], _),
187 wd_and_efficient(BOP), % should not generate WD errors itself
188 ? select(contains_wd_condition,Infos,NewInfos), % there is a WD condition attached
189 fast_check_wd(A), fast_check_wd(B),
190 %print(removing_wd_condition(BOP)),nl,
191 !.
192 update_infos(_,I,_,I).
193
194 update_infos_aux(EParas,Cond,Infos,Parameters,NewInfos) :-
195 select_used_ids(UsedIds,Infos,I1,EParas,Cond),
196 UsedIds \= [],!,
197 % remove those used identifiers which will be compiled into the predicate
198 sort(Parameters,SParas),
199 ord_intersection(UsedIds,SParas,NewUsedIds),
200 %print(update(Parameters,UsedIds,I1,new(NewUsedIds))),nl,
201 NewInfos = [used_ids(NewUsedIds)|I1].
202
203 :- use_module(bsyntaxtree,[find_identifier_uses/3]).
204 ?select_used_ids(UsedIds,Infos,I1,_,_) :- select(used_ids(UsedIds),Infos,I1),!.
205 % check_used_ids_info(Parameters,Condition,UsedIds,b_compiler)
206 select_used_ids(UsedIds,Infos,Infos,_Parameters,Condition) :-
207 %add_error(bcompiler,'Expected information of used identifiers in exists operation information : ',Parameters:Infos), %% missing info can happen due to simplifcation rules below !
208 find_identifier_uses(Condition, [], UsedIds). % ,print(used(UsedIds,in_exist(Parameters))),nl.
209 % TO DO: avoid re-computing used-ids; we should refactor b_compile2 to return new Info field
210
211 %is_pred(b(_,pred,_)).
212
213
214 evaluate_this(eval,X,Type,Info) :- !, worth_it_type(Type,X,Info).
215 evaluate_this(_,X,_Type,_Info) :- wd_and_efficient(X).
216
217
218 % things which are very quick to compute
219 wd_and_efficient(sequence_extension(_)) :- !.
220 wd_and_efficient(integer_set(_)) :- !. % will be converted into value(global_set(_))
221 %% wd_and_efficient(value(_)) :- !. % is already computed
222 % the following will reduce the size of the representation; usually a good thing;
223 % we assume only avl_sets apprear here; inner set comprehensions are never computed into symbolic form by b_compile (see known_value below):
224 %wd_and_efficient(identity(_)) :- !.
225 wd_and_efficient(range(_)) :- !.
226 wd_and_efficient(domain(_)) :- !.
227 wd_and_efficient(domain_restriction(_,_)) :- !.
228 wd_and_efficient(domain_subtraction(_,_)) :- !.
229 wd_and_efficient(range_restriction(_,_)) :- !.
230 wd_and_efficient(range_subtraction(_,_)) :- !.
231 wd_and_efficient(intersection(_,_)) :- !.
232 wd_and_efficient(set_subtraction(_,_)) :- !.
233 wd_and_efficient(image(_,_)) :- !.
234 % what about union: usually the union of two avl_sets will be smaller than keeping them separate
235 % some other efficient operators:
236 wd_and_efficient(X) :- worth_it_int(X),!.
237 wd_and_efficient(X) :- worth_it_other(X).
238
239 fast_check_wd(b(E,_,Infos)) :-
240 (nonmember(contains_wd_condition,Infos) -> true ; nonvar(E), E= value(_)).
241
242 check_wd(NTExpr) :- bsyntaxtree:always_well_defined(NTExpr). % ,print(wd(NTExpr)),nl.
243 %(bsyntaxtree:always_well_defined(NTExpr) -> true ; print(not_guaranteed_wd(NTExpr)),nl).
244
245 % (worth_it_type(Type,X,Info) -> true ; X=value(_) -> true ; print(not_evaluating(X)),nl,fail).
246 worth_it_type(integer,X,Info) :- worth_it_int_wd(X),!, check_wd(b(X,integer,Info)).
247 worth_it_type(T,function(A,B),Info) :- !,
248 (check_wd(b(function(A,B),T,Info)) -> true
249 ; fail). %print('not_precompiling_function '),translate:print_bexpr(A), print(' @ '), translate:print_bexpr(B),nl,fail).
250 worth_it_type(integer,X,_) :- worth_it_int(X),!.
251 worth_it_type(T,X,Info) :- worth_it_wd(X),!, check_wd(b(X,T,Info)).
252 worth_it_type(set(_),X,_) :- worth_it_set(X),!.
253 worth_it_type(seq(_),X,_) :- worth_it_set(X),!.
254 worth_it_type(_,X,_) :- worth_it_other(X).
255
256 % TO DO: we should use the predicate has_wd_condition from b_ast_cleanup
257
258 % integer operations that could generate WD-errors
259 worth_it_int_wd(div(_,_)).
260 worth_it_int_wd(max(_)).
261 worth_it_int_wd(min(_)).
262 worth_it_int_wd(mod(_,_)).
263 worth_it_int_wd(power_of(_,_)).
264 worth_it_int_wd(card(_)). % has WD condition !!
265 worth_it_int_wd(size(_)).
266
267 % other operations that could generate WD-errors
268 worth_it_wd(first(_)).
269 worth_it_wd(last(_)).
270 worth_it_wd(tail(_)).
271 worth_it_wd(front(_)).
272 worth_it_wd(restrict_front(_,_)).
273 worth_it_wd(restrict_tail(_,_)).
274 worth_it_wd(rel_iterate(_,_)). %% could be expensive
275 worth_it_wd(general_intersection(_)).
276 worth_it_wd(general_concat(_)).
277
278 % to do: check other operators that could be not well-defined !
279
280 worth_it_int(unary_minus(_)).
281 worth_it_int(add(_,_)).
282 worth_it_int(minus(_,_)).
283 worth_it_int(multiplication(_,_)).
284 worth_it_int(max_int).
285 worth_it_int(min_int).
286
287 %worth_it_set(empty_set). % treated below
288 %worth_it_set(empty_sequence). % treated below
289 %worth_it_set(closure(_)). % this is closure1; it is currently always kept symbolic and can be counterproductive to compile; e.g., card(closure1(%x.(x : 1 .. 200|x + 1)))
290 %% ?? need to be more careful here; can be expensive --> need to keep track which parts need definitely to be evaluated
291 worth_it_set(integer_set(_)). % will be converted into value(global_set(_))
292 worth_it_set(comprehension_set(A,B)) :- b_ast_cleanup:is_integer_set(comprehension_set(A,B),_).
293 worth_it_set(interval(_,_)).
294 worth_it_set(reflexive_closure(_)).
295 worth_it_set(reverse(_)).
296 worth_it_set(domain(_)). worth_it_set(range(_)).
297 worth_it_set(union(_,_)). worth_it_set(intersection(_,_)). worth_it_set(set_subtraction(_,_)).
298 worth_it_set(image(_,_)). worth_it_set(composition(_,_)).
299 worth_it_set(domain_restriction(_,_)). worth_it_set(domain_subtraction(_,_)).
300 worth_it_set(range_restriction(_,_)). worth_it_set(range_subtraction(_,_)).
301 worth_it_set(direct_product(_,_)). worth_it_set(parallel_product(_,_)).
302 worth_it_set(iteration(_,_)).
303 worth_it_set(set_extension(_)).
304 worth_it_set(sequence_extension(_)).
305 worth_it_set(rev(_)).
306 worth_it_set(concat(_,_)).
307 worth_it_set(seq(_)). % will be kept symbolic anyway
308 worth_it_set(seq1(_)). % will be kept symbolic anyway
309 worth_it_set(iseq(_)). % will be kept symbolic anyway
310 worth_it_set(iseq1(_)). % will be kept symbolic anyway
311 worth_it_set(perm(_)). % will be kept symbolic anyway
312 worth_it_set(pow_subset(_)). % will be kept symbolic anyway
313 worth_it_set(pow1_subset(_)). % will be kept symbolic anyway
314 worth_it_set(fin_subset(_)). % will be kept symbolic anyway
315 worth_it_set(fin1_subset(_)). % will be kept symbolic anyway
316 worth_it_set(general_union(_)).
317 worth_it_set(identity(_)).
318 worth_it_set(first_of_pair(_)). % can also produce set
319 worth_it_set(second_of_pair(_)). % can also produce set
320 worth_it_set(cartesian_product(_,_)). % will usually be kept symbolic
321 worth_it_set(string_set). % ensure we have values inside compiled closures, e.g., for custom_explicit_set card computations
322 worth_it_set(bool_set).
323
324 :- use_module(external_functions,[not_declarative/1,external_fun_has_wd_condition/1]).
325 worth_it_other(boolean_true).
326 worth_it_other(boolean_false).
327 worth_it_other(string(_)).
328 worth_it_other(first_of_pair(_)).
329 worth_it_other(second_of_pair(_)).
330 worth_it_other(couple(_,_)).
331 worth_it_other(record_field(_,_)).
332 worth_it_other(external_function_call(FunName,_)) :-
333 \+ not_declarative(FunName),
334 \+ external_fun_has_wd_condition(FunName). %print(compile(FunName)),nl.
335 worth_it_other(rec(_)).
336 worth_it_other(struct(_)).
337 %worth_it_other(value(_)). % does not have to be evaluted; already a value
338
339 /*
340 % To do: distinguish which parts definitely need to be evaluated
341 %dont_eval_subexpressions(member). % special membership code can be used
342 %dont_eval_subexpressions(not_member). % special membership code can be used
343 dont_eval_subexpressions(disjunct(_,_)). % it may not be necessary to eval RHS
344 dont_eval_subexpressions(implication(_,_)). % it may not be necessary to eval RHS
345 */
346
347 :- use_module(kernel_objects,[equal_object/3]).
348 :- use_module(kernel_mappings,[binary_boolean_operator/3]).
349 :- use_module(kernel_tools,[filter_cannot_match/4, get_template_for_filter_cannot_match/2]).
350 b_compile2(Exp,Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- var(Exp), !,
351 add_internal_error('Variable Expression: ',b_compile2(Exp,Parameters,LS,S,NExpr,Eval,FullyKnown,WF)),
352 NExpr=Exp, FullyKnown=false.
353 b_compile2(truth,_,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !, NExpr=truth, FullyKnown=false. % predicates never fully known
354 b_compile2(falsity,_,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !, NExpr=falsity, FullyKnown=false. % predicates never fully known
355 b_compile2(empty_set,_,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !, NExpr=value([]), FullyKnown=true.
356 b_compile2(empty_sequence,_,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !, NExpr=value([]), FullyKnown=true.
357 b_compile2(value(Val),_Parameters,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !,
358 NExpr=value(Val),
359 (known_value(Val) -> % ground(Val) -> known_value ?
360 FullyKnown=true ; FullyKnown=false).
361 b_compile2(integer(Val),_Parameters,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !,
362 NExpr=value(int(Val)), (number(Val) -> FullyKnown=true ; FullyKnown=false).
363 b_compile2(lazy_lookup_pred(Id),Parameters,LS,S,NExpr,_Eval,FullyKnown,_WF) :- !,
364 ( memberchk(Id,Parameters) -> %print(lazy_lookup_pred_id_as_parameter(Id,Parameters)),nl,
365 NExpr = lazy_lookup_pred(Id), FullyKnown=false
366 ; otherwise -> compute_lazy_lookup(Id,lazy_lookup_pred(Id),LS,S,NExpr,FullyKnown)
367 ).
368 b_compile2(lazy_lookup_expr(Id),Parameters,LS,S,NExpr,_Eval,FullyKnown,_WF) :- !,
369 ( memberchk(Id,Parameters) -> %print(lazy_lookup_expr_id_as_parameter(Id,Parameters)),nl,
370 NExpr = lazy_lookup_expr(Id), FullyKnown=false
371 ; otherwise -> compute_lazy_lookup(Id,lazy_lookup_expr(Id),LS,S,NExpr,FullyKnown)
372 ).
373 % treat a few common cases, more efficiently than syntaxtransformation
374 b_compile2(equal(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
375 FullyKnown=false, % predicates never evaluated in b_compile1
376 b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnownA,WF),
377 b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnownB,WF),
378 ( FullyKnownA=true, FullyKnownB=true,
379 NExprA = b(value(VA),_,_), NExprB = b(value(VB),_,_)
380 -> %print(computing_eq(VA,VB)),nl,
381 (equal_object(VA,VB,b_compile2_1) -> NExpr = truth ; NExpr = falsity)
382 %, print(result(NExpr)),nl
383 ; generate_equality(NExprA,NExprB,NExpr)
384 ).
385 b_compile2(not_equal(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
386 FullyKnown=false, % predicates never evaluated in b_compile1
387 b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnownA,WF),
388 b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnownB,WF),
389 ( FullyKnownA=true, FullyKnownB=true,
390 NExprA = b(value(VA),_,_), NExprB = b(value(VB),_,_)
391 -> %print(computing_neq(VA,VB)),nl,
392 (kernel_objects:equal_object(VA,VB,b_compile2_2) -> NExpr = falsity ; NExpr = truth)
393 %, print(result(NExpr)),nl
394 ; NExpr = not_equal(NExprA,NExprB)
395 ).
396 b_compile2(member(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
397 FullyKnown=false, % predicates never evaluated in b_compile1
398 b_compile1(B,Parameters,LS,S,NExprB,Eval,_,WF),
399 (NExprB = b(value(X),BT,BI)
400 -> (X==[], always_well_defined(A) -> NExpr = falsity
401 ; b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF),
402 % check if we can decide membership (e.g., 1:{1})
403 ? (quick_test_membership1(NExprA,X,PRes)
404 -> convert_pred_res(PRes,NExpr)
405 % TO DO: maybe optimize x: {y|P(y)} --> P(x) ; by commenting in code below
406 % However, ensure test 273 succeeds and closure equality correctly detected (e.g., for BV16 = {bt|bt : BIT_VECTOR & bv_size(bt) = 16})
407 % ; (get_texpr_id(NExprA,IDA),
408 % get_comprehension_set(NExprB,IDB,Pred), get_texpr_info(NExprB,Info),
409 % print(rename(IDB,IDA,Info)),nl,
410 % bsyntaxtree:rename_bt(Pred,[rename(IDB,IDA)],PredA)) -> get_texpr_expr(PredA,NExpr)
411 ; custom_explicit_sets:singleton_set(X,El) % replace x:{El} -> x=El
412 -> get_texpr_type(NExprA,TA), NExpr = equal(NExprA,b(value(El),TA,[]))
413 ; get_template_for_filter_cannot_match(NExprA,VA)
414 -> filter_cannot_match(X,VA,NewX,Filtered),
415 % (Filtered=false -> true ; print(filtered(NewX,VA,X)),nl),
416 (Filtered=false -> NExpr = member(NExprA,NExprB)
417 ; (NewX==[], always_well_defined(A)) -> NExpr = falsity
418 ; custom_explicit_sets:singleton_set(NewX,El)
419 -> get_texpr_type(NExprA,TA), NExpr = equal(NExprA,b(value(El),TA,[]))
420 ; otherwise -> NExpr = member(NExprA, b(value(NewX),BT,BI))
421 )
422 % end fo filtering
423 ; NExpr = member(NExprA,NExprB)
424 )
425 % , print('compile: '),print(NExpr),nl
426 )
427 ; NExpr = member(NExprA,NExprB),
428 b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF)
429 ).
430 % TO DO: also optimize things like: (ev1 |-> 0) |-> eg : #221:{((1|->0)|->3),((2|->0)|->0),...,((233|->0)|->218),((234|->0)|->228)}
431
432 b_compile2(not_member(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
433 FullyKnown=false, % predicates never evaluated in b_compile1
434 b_compile1(B,Parameters,LS,S,NExprB,Eval,_,WF),
435 (NExprB = b(value(X),_,_)
436 -> (X==[], always_well_defined(A) -> NExpr = truth
437 ; b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF),
438 (quick_test_membership1(NExprA,X,PRes)
439 -> convert_neg_pred_res(PRes,NExpr)
440 ; NExpr = not_member(NExprA,NExprB))
441 )
442 ; NExpr = not_member(NExprA,NExprB),
443 b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF)
444 ).
445 b_compile2(function(Fun,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
446 (is_extension_function_gt1(Fun) -> Eval1=false % extension function applications treated lazily
447 % TO DO: first evaluate B, if known then only evaluate relevant part of extension function
448 ; Eval1=Eval),
449 b_compile1(Fun,Parameters,LS,S,NExprA,Eval1,FullyKnown1,WF),
450 combine_fully_known(FullyKnown1,FullyKnown2,FullyKnown12),
451 b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnown2,WF),
452 %tools_printing:print_term_summary(compiled_function(FullyKnown1,FullyKnown2,NExprA,NExprB)),nl,
453 (FullyKnown2=true, preferences:preference(find_abort_values,false),
454 % check if we have enough information to apply a partially specified function as a list
455 % e.g. if the function is [(int(1),A),(int(2),B)] and the argument is int(2): we can apply the function without knowing A or B; can have a dramatic importance when expanding unversal quantifiers !
456 can_apply_partially_specified_function(NExprA,NExprB,ResultExpr,WF)
457 -> NExpr = ResultExpr,
458 (FullyKnown12=true -> FullyKnown=true
459 ; ResultExpr=value(ResultValue),known_value(ResultValue) -> FullyKnown=true
460 ; FullyKnown = false)
461 ; % print(cannot_apply_function(NExprA,NExprB,FullyKnown2)),nl,
462 NExpr = function(NExprA,NExprB), FullyKnown = FullyKnown12).
463
464 b_compile2(conjunct(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
465 FullyKnown=false, % predicates never automatically evaluated in b_compile1
466 b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF),
467 (is_falsity(NExprA) -> NExpr = falsity
468 ;
469 % TO DO: propagate static information from A to B, e.g. if A :: x=10 -> add x=10 to LS/Parameters
470 % also: try and detect unsatisfiable predicates beforehand
471 b_compile1(B,Parameters,LS,S,NExprB,Eval,_,WF),
472 (is_falsity(NExprB) -> NExpr = falsity
473 ; is_truth(NExprB) -> get_texpr_expr(NExprA,NExpr)
474 ; is_truth(NExprA) -> get_texpr_expr(NExprB,NExpr)
475 ; NExpr = conjunct(NExprA,NExprB))
476 ).
477 b_compile2(disjunct(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
478 FullyKnown=false, % predicates never automatically evaluated in b_compile1
479 b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF),
480 (is_truth(NExprA) -> NExpr = truth
481 ; b_compile1(B,Parameters,LS,S,NExprB,false,_,WF), % does not have to be executed in a successful branch: set Eval to false to avoid computing expensive expressions which may not be needed
482 (is_truth(NExprB) -> NExpr = truth
483 ; is_falsity(NExprA) -> get_texpr_expr(NExprB,NExpr)
484 ; is_falsity(NExprB) -> get_texpr_expr(NExprA,NExpr)
485 ; NExpr = disjunct(NExprA,NExprB))
486 ).
487 b_compile2(implication(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
488 FullyKnown=false, % predicates never automatically evaluated in b_compile1
489 b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF),
490 (is_falsity(NExprA) -> NExpr = truth
491 ; is_truth(NExprA) -> b_compile1(B,Parameters,LS,S,NExprB,false,_,WF), get_texpr_expr(NExprB,NExpr)
492 ; NExpr = implication(NExprA,NExprB),
493 b_compile1(B,Parameters,LS,S,NExprB,false,_,WF) % does not have to be executed in a succesful branch: set Eval to false to avoid computing expensive expressions which may not be needed
494 ).
495 b_compile2(negation(A),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
496 FullyKnown=false, % predicates never automatically evaluated in b_compile1
497 b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF),
498 ( get_negated_expr(NExprA,NegatedA) -> NExpr = NegatedA
499 ; NExpr = negation(NExprA)
500 ).
501
502 /* b_compile2(comprehension_set(CParas,Body),Parameters,LS,S,NExpr,_Eval,FullyKnown,WF) :-
503 sort(Parameters,SParas),
504 b_ast_cleanup:not_occurs_in_predicate(SParas,Body), %can only be applied if Body does not reference Parameters
505 !,
506 b_generate_inner_closure_if_necessary(Parameters,CParas,Body,LS,S,Result), % will itself call b_compile
507 NExpr = value(Result),
508 (ground(Result) -> FullyKnown=true ; FullyKnown=false). */
509 b_compile2(forall(ForallPara,A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
510 FullyKnown=false, % predicates never automatically evaluated in b_compile1
511 get_texpr_ids(ForallPara,AtomicIds),
512 append(Parameters,AtomicIds,NParameters),
513 b_compile1(A,NParameters,LS,S,NA,Eval,_FullyKnownA,WF),
514 (is_falsity(NA) -> NExpr = truth
515 ; b_compile1(B,NParameters,LS,S,NB,Eval,_FullyKnownB,WF),
516 (is_truth(NB) -> NExpr = truth
517 ; NExpr = forall(ForallPara,NA,NB)
518 % TO DO ??: if we have an equality -> replace Body by value and remove quantifier
519 %,print('COMPIlED: '),translate:print_bexpr(b(NExpr,pred,[])),nl
520 )
521 ).
522 % some special cases to avoid calling syntaxtransformation
523 b_compile2(record_field(A,FieldName),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
524 b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnownA,WF),
525 % First: we can try compute even if value not fully known !, we just need record field list
526 (get_record_field(NExprA,FieldName,NExpr,FullyKnown) -> true
527 ; NExpr = record_field(NExprA,FieldName), FullyKnown=FullyKnownA).
528 %((FullyKnown=false,NExprA=b(VV,_,_),nonvar(VV),VV=value(V)) , trace, known_value(V) ; true).
529 b_compile2(couple(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
530 %NExpr = couple(NExprA,NExprB),
531 b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnown1,WF),
532 combine_fully_known(FullyKnown1,FullyKnown2,FullyKnown),
533 b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnown2,WF),
534 (FullyKnown \== true, % evaluation will already combine the result
535 NExprA=b(value(VA),_,_),NExprB=b(value(VB),_,_)
536 -> NExpr = value((VA,VB))
537 ; NExpr = couple(NExprA,NExprB)).
538 b_compile2(image(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
539 %NExpr = image(NExprA,NExprB),
540 b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnown1,WF),
541 combine_fully_known(FullyKnown1,FullyKnown2,FullyKnown),
542 b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnown2,WF),
543 (FullyKnown \= true, NExprA=b(value(VA),BT,BI),
544 NExprB=b(value(VB),_,_), nonvar(VB),
545 custom_explicit_sets:singleton_set(VB,VBX)
546 -> filter_cannot_match(VA,(VBX,_),NewVA,_Filtered), %nl,print(filtered_image(VBX,VA,NewVA)),nl,
547 NExpr = image(b(value(NewVA),BT,BI),NExprB)
548 % TO DO: add case where VB==[] or VA==[] are the empty set
549 ; NExpr = image(NExprA,NExprB)
550 ). %, print('compile image: '),translate:print_bexpr(NExpr),nl.
551 % TO DO: do something like can_apply_partially_specified_function; or filter_can_match
552 b_compile2(domain(A),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
553 b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnown1,WF),
554 (FullyKnown1=false,get_texpr_expr(NExprA,NA),evaluate_domain(NA,Domain) % try and compute domain even if not fully known
555 -> FullyKnown = true, NExpr = value(Domain)
556 ; FullyKnown = FullyKnown1, NExpr = domain(NExprA)).
557 b_compile2(range(A),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
558 b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnown1,WF),
559 (FullyKnown1=false,evaluate_range(NExprA,Range) % try and compute range even if not fully known
560 -> FullyKnown = true, NExpr = value(Range)
561 ; FullyKnown = FullyKnown1, NExpr = range(NExprA)).
562 b_compile2(assign(LHS_List,RHS_List),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !,
563 %print(compile_assign(LHS_List)),nl,
564 NExpr = assign(New_LHS_List,NewRHS_List), FullyKnown = false,
565 maplist(b_compile_lhs(Parameters,LS,S,Eval,WF),LHS_List,New_LHS_List),
566 b_compile_l(RHS_List,Parameters,LS,S,NewRHS_List,Eval,_FullyKnown2,WF).
567 b_compile2(assign_single_id(ID,B),Parameters,LS,S,assign_single_id(ID,NExprB),Eval,FullyKnown,WF) :- !,
568 FullyKnown = false,
569 b_compile1(B,Parameters,LS,S,NExprB,Eval,_,WF).
570 b_compile2(operation_call(Operation,OpCallResults,OpCallParas),Parameters,LS,S,InlinedOpCall,Eval,FullyKnown,WF) :-
571 %print(opcall(Operation,OpCallResults,OpCallParas)),nl,
572 % TO DO: evaluate if we should also use the let_expression_global approach used for operation_call_in_expr
573 !,
574 def_get_texpr_id(Operation,op(OperationName)),
575 FullyKnown = false,
576 b_compile_l(OpCallParas,Parameters,LS,S,OpCallParaValues,Eval,_,WF),
577 TopLevel=false,
578 b_get_machine_operation_for_animation(OperationName,OpResults,OpFormalParameters,Body,_OType,TopLevel),
579 bsyntaxtree:replace_ids_by_exprs(Body,OpResults,OpCallResults,Body2),
580 get_texpr_ids(OpFormalParameters,OpIds),
581 append(OpIds,Parameters,InnerParas),
582 b_compile1(Body2,InnerParas,[],S,NBody,Eval,FullyKnown,WF), % do not pass local state: this may override constants,... from the called machine
583 % Note: global state S should be valid for all machines in currently loaded specification
584 get_texpr_ids(OpCallResults,OpRIds),
585 append(OpRIds,Parameters,LocalKnownParas),
586 simplify_assignment(OpFormalParameters,OpCallParaValues,LHSFormalParas,RHSCallVals), %%
587 split_formal_parameters(LHSFormalParas,RHSCallVals,LocalKnownParas,
588 FreshOpParas,FreshCallVals,
589 ClashOpParas, ClashCallVals), % only set up VAR for fresh Paras
590 % print(split(LHSFormalParas,LocalKnownParas,fresh(FreshOpParas),clash(ClashOpParas))),nl,
591 (FreshOpParas=[] -> get_texpr_expr(NBody,Let1)
592 ; create_equality_for_let(FreshOpParas,FreshCallVals,Equality1),
593 Let1 = let(FreshOpParas,Equality1,NBody)),
594 (ClashOpParas = []
595 -> InlinedOpCall = Let1
596 ; %nl,print(clash(ClashOpParas)),nl,
597 maplist(create_fresh_id,ClashOpParas,FreshCopy),
598 create_equality_for_let(ClashOpParas,FreshCopy,Equality2), % copy Values from Fresh Ids
599 create_equality_for_let(FreshCopy,ClashCallVals,Equality3), % assign Parameter Vals to Fresh Ids
600 get_texpr_pos(Body,BodyPos), BodyPosInfo = [nodeid(BodyPos)],
601 Let2 = let(ClashOpParas,Equality2,b(Let1,subst,[BodyPosInfo])),
602 InlinedOpCall = let(FreshCopy,Equality3,b(Let2,subst,[BodyPosInfo]))
603 ).
604 %, print('Compiled operation call: '), translate:print_subst(b(InlinedOpCall,subst,BodyPosInfo)),nl,nl.
605 % Maybe this version is faster when no OpCallResults:
606 %b_compile2(operation_call(Operation,OpCallResults,OpCallParas),Parameters,LS,S,InlinedOpCall,Eval,FullyKnown,WF) :-
607 % OpCallResults=[],
608 % !,
609 % def_get_texpr_id(Operation,op(OperationName)),
610 % FullyKnown = false,
611 %% b_compile_l(Results,Parameters,LS,S,NResults,Eval,_,WF),
612 % b_compile_l(OpCallParas,Parameters,LS,S,OpCallParaValues,Eval,_,WF),
613 % TopLevel=false,
614 % b_get_machine_operation_for_animation(OperationName,OpResults,OpParameters,Body,_OType,TopLevel),
615 % % Note: input parameters cannot be assigned to: so replace ids is ok
616 % % However, we cannot replace output parameters: these can be assigned to and we can have aliasing
617 % % Note: no aliasing is allowed in OpCallResults (cf Atelier-B handbook x,x <-- op not allowed)
618 % bsyntaxtree:replace_ids_by_exprs(Body,OpParameters,OpCallParaValues,Body2),
619 % get_texpr_ids(OpResults,OpIds),
620 % append(OpIds,Parameters,InnerParas),
621 % b_compile1(Body2,InnerParas,LS,S,NBody,Eval,FullyKnown,WF),
622 % FinalBody = NBody.
623 b_compile2(Expr,Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :-
624 functor(Expr,BOP,2),
625 binary_boolean_operator(BOP,_,_),!, % from kernel_mappings, slightly more efficient than syntaxtransformation
626 arg(1,Expr,A),
627 FullyKnown=false, % predicates never evaluated in b_compile1
628 b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnownA,WF),
629 arg(2,Expr,B),
630 b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnownB,WF),
631 (eval_binary_bool(FullyKnownA,NExprA,FullyKnownB,NExprB,BOP,Result)
632 -> NExpr = Result
633 ; functor(NExpr,BOP,2), arg(1,NExpr,NExprA), arg(2,NExpr,NExprB)
634 ).
635 b_compile2(Expr,Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :-
636 functor(Expr,BOP,2),
637 kernel_mappings:binary_function(BOP,_,_),!, % slightly more efficient than syntaxtransformation
638 arg(1,Expr,A),
639 b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnownA,WF),
640 combine_fully_known(FullyKnownA,FullyKnownB,FullyKnown),
641 arg(2,Expr,B),
642 b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnownB,WF),
643 functor(NExpr,BOP,2), arg(1,NExpr,NExprA), arg(2,NExpr,NExprB).
644 b_compile2(Expr,Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :-
645 functor(Expr,UOP,1),
646 kernel_mappings:unary_function(UOP,_,_),!, % slightly more efficient than syntaxtransformation
647 arg(1,Expr,A),
648 b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnown,WF),
649 functor(NExpr,UOP,1), arg(1,NExpr,NExprA).
650 b_compile2(Expr,Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- % GENERAL CASE
651 %hit_profiler:add_profile_hit(Expr),
652 syntaxtransformation(Expr,Subs,Names,NSubs,NExpr),
653 get_texpr_ids(Names,Ids), append(Parameters,Ids,NParameters),
654 b_compile_l(Subs,NParameters,LS,S,NSubs,Eval,FullyKnown,WF).
655
656 b_compile_l([],_,_,_,[],_Eval,true,_WF).
657 b_compile_l([Expr|ExprRest],P,LS,S,[NExpr|NExprRest],Eval,FullyKnown,WF) :-
658 b_compile1(Expr,P,LS,S,NExpr,Eval,FullyKnown1,WF),
659 combine_fully_known(FullyKnown1,FullyKnown2,FullyKnown),
660 b_compile_l(ExprRest,P,LS,S,NExprRest,Eval,FullyKnown2,WF).
661
662 % detecth when a parameter clashes with existing known ids
663 id_clash(LocalKnownParas,TID) :- def_get_texpr_id(TID,ID), member(ID,LocalKnownParas).
664
665 /* comment in if we want to compile inner comprehension sets:
666 :- use_module(closures,[construct_closure_if_necessary/4]).
667 b_generate_inner_closure_if_necessary(OuterParameters,ClosureParas,Condition,LocalState,State,Result) :-
668 split_names_and_types(ClosureParas,Names,Types),
669 append(OuterParameters,Names,FullNames),
670 b_compile(Condition,FullNames,LocalState,State,ClosurePred),
671 print('INNER COMPILE: '), translate:print_bexpr(ClosurePred),nl,
672 construct_closure_if_necessary(Names,Types,ClosurePred,Result).
673 */
674
675
676 % the LHS contains l-values which should not be looked up in the environment
677 % however, we need to deal with things like f(i) := RHS and compile i
678 b_compile_lhs(Parameters,LS,S,Eval,WF,TExpr,NewTExpr) :-
679 TExpr = b(Expr,Type,Info), NewTExpr = b(NewExpr,Type,Info),
680 b_compile_lhs_aux(Expr,Parameters,LS,S,NewExpr,Eval,WF).
681
682 b_compile_lhs_aux(function(A,B),Parameters,LS,S,function(NewA,NewB),Eval,WF) :- !,
683 b_compile_lhs(Parameters,LS,S,Eval,WF,A,NewA), % we can have nexted function calls f(e)(g) :=
684 b_compile1(B,Parameters,LS,S,NewB,Eval,_,WF).
685 b_compile_lhs_aux(E,_,_,_,E,_,_WF). % other LHS should be identifier -> just copy
686
687 get_record_field(b(value(Val),_,_),FieldName,value(Field),FullyKnown) :- !,
688 nonvar(Val), Val=rec(Fields),
689 safe_get_field(Fields,FieldName,Field),
690 known_value(Field,FullyKnown).
691 get_record_field(b(function(FUN,ARG),_Type,_Info),FieldName,function(ReducedFUN,ARG),false) :-
692 % {1|->rec(a:1,b:2),...}(x)'b --> {1|->2,...}(x)
693 %nl,print(get_field(FUN,ARG,FieldName)),nl,
694 % TO DO: also allow nested functions calls {1|->rec(a:1,b:2),...}(x)(y)'b or other reduction operators
695 get_field_in_range(FUN,FieldName,ReducedFUN).
696 safe_get_field(V,_,_) :- var(V),!,fail.
697 safe_get_field([field(N,V)|T],FieldName,Result) :- nonvar(N),
698 (N=FieldName -> Result=V ; safe_get_field(T,FieldName,Result)).
699
700 :- use_module(probsrc(custom_explicit_sets),[expand_custom_set_to_list/4, convert_to_avl/2]).
701 :- use_module(probsrc(avl_tools),[avl_height_less_than/2]).
702 get_field_in_range(b(value(OldVal),set(couple(Dom,OldRange)),Info),FieldName,
703 b(value(NewVal),set(couple(Dom,NewRange)),Info)) :-
704 nonvar(OldVal), OldVal=avl_set(AVL),
705 avl_height_less_than(AVL,10),
706 OldRange = record(Fields),
707 member(field(FieldName,NewRange),Fields),!,
708 expand_custom_set_to_list(avl_set(AVL),List,_,get_field_in_range),
709 maplist(safe_get_range_field(FieldName),List,NewList),
710 %print(reduced_get_field_in_range(NewList)),nl,
711 convert_to_avl(NewList,NewVal).
712
713 % compute the field access for the range elements:
714 safe_get_range_field(FieldName,(Dom,rec(Fields)),(Dom,Field)) :- safe_get_field(Fields,FieldName,Field).
715
716
717 eval_binary_bool(true,b(value(ValA),_,_),true,b(value(ValB),_,_),BOP,Result) :-
718 eval_binary_aux(BOP,ValA,ValB,Result).
719 %print(eval(BOP,ValA,ValB,Result)),nl,nl.
720 eval_binary_aux(less,int(A),int(B),Result) :-
721 (A < B -> Result = truth ; Result = falsity).
722 eval_binary_aux(greater,int(A),int(B),Result) :-
723 (A > B -> Result = truth ; Result = falsity).
724 eval_binary_aux(less_equal,int(A),int(B),Result) :-
725 (A =< B -> Result = truth ; Result = falsity).
726 eval_binary_aux(greater_equal,int(A),int(B),Result) :-
727 (A >= B -> Result = truth ; Result = falsity).
728 % TO DO: other operators are subset, strict_subset, ...
729
730 get_negated_expr(b(E,pred,_),Res) :- negate_expr_aux(E,Res).
731 negate_expr_aux(falsity,truth).
732 negate_expr_aux(truth,falsity).
733 negate_expr_aux(member(X,S),not_member(X,S)).
734 negate_expr_aux(not_member(X,S),member(X,S)).
735 negate_expr_aux(subset(X,S),not_subset(X,S)).
736 negate_expr_aux(not_subset(X,S),subset(X,S)).
737 negate_expr_aux(subset_strict(X,S),not_subset_strict(X,S)).
738 negate_expr_aux(not_subset_strict(X,S),subset_strict(X,S)).
739 negate_expr_aux(equal(X,S),not_equal(X,S)).
740 negate_expr_aux(not_equal(X,S),equal(X,S)).
741 negate_expr_aux(less(X,S),greater_equal(X,S)).
742 negate_expr_aux(greater_equal(X,S),less(X,S)).
743 negate_expr_aux(less_equal(X,S),greater(X,S)).
744 negate_expr_aux(greater(X,S),less_equal(X,S)).
745
746 :- use_module(store,[lookup_value_for_existing_id/4]).
747 compute_lazy_lookup(Id,Expr,LS,S,NExpr,FullyKnown) :-
748 lookup_value_for_existing_id(Id,LS,S,(Evaluated,Value)),
749 !,
750 known_value(Value,FullyKnown),
751 (Evaluated==pred_true -> NExpr = value(Value)
752 ; FullyKnown==true -> NExpr = value(Value)
753 ; memberchk('$do_not_force_lazy_lookups',LS) -> NExpr = Expr % we do not force lookup: there could be WD issues ! TO DO: examine Infos for wd_condition
754 %, print(not_forcing(Id,Value)),nl
755 ; if(Evaluated = pred_true, % will force evaluation ! Note: this means shared expression inside a compiled expression must be well-defined
756 NExpr = value(Value),
757 (add_internal_error('Compilation failed: ',compute_lazy_lookup(Id,Expr,LS,S,NExpr,FullyKnown) ),
758 fail))
759 ).
760 compute_lazy_lookup(Id,E,LS,S,LazyValue,_) :-
761 add_internal_error('Compilation failed, illegal lazy_lookup_value: ',compute_lazy_lookup(Id,E,LS,S,LazyValue,_)),
762 fail.
763
764 combine_fully_known(true,A,A).
765 combine_fully_known(false,_,false).
766
767 % is an extension function with at least two elements
768 is_extension_function_gt1(b(A,_,_Info)) :- is_extension_function_aux(A).
769 is_extension_function_aux(set_extension([_,_|_])).
770 is_extension_function_aux(sequence_extension([_,_|_])).
771
772 :- use_module(bsyntaxtree,[is_set_type/2]).
773 % check if we can apply an argument to a partially specified function (as a list)
774 %can_apply_partially_specified_function(Fun,X,_) :- print(fun(Fun)),nl,print(val(X)),nl,fail.
775 can_apply_partially_specified_function(b(Expr,TYPE,_), b(value(X),TA,_),ResultExpr,WF) :-
776 can_apply_aux(Expr,TYPE,X,TA,ResultExpr,WF).
777
778 can_apply_aux(value(VAL),TYPE,X,TA,value(ResultValue),WF) :-
779 is_set_type(TYPE,couple(TA,_TB)),
780 lookup_result(VAL,X,ResultValue,WF).
781 can_apply_aux(sequence_extension(List),_,X,integer,ResultExpr,_WF) :- % important, e.g., for solving test 1551: {b|[a,b,c](2)=333} =res & a : res & b:res
782 nonvar(X), X=int(Index), number(Index),
783 % this will prevent computing rest of sequence extension: can hide WD issues !
784 % print(apply_seq_extension(Index,List)),nl,
785 nth1(Index,List,b(ResultExpr,_,_)).
786
787 :- use_module(kernel_equality,[equality_objects_wf/4]).
788 %lookup_result(VAR,ArgValue,Result,WF) :- var(VAR),!,kernel_mappings:kernel_call_apply_to(VAR,ArgValue,Result,unknown,unknown,WF).
789 % the clause above is unsound; as apply_to CAN RAISE WD ERRORS !! what if we have IF 1:dom(f) THEN f(1) ELSE f(0) END; we do not want to compute f(1) ! it can also instantiate unbound variables !
790 % the idea was to avoid that we wait on the full function, before compiled closure can be evaluated; test 1552
791 % important for e.g. a = {(1, {([]|->2)} ), (2, const(1, [a(1)]))}
792 % or: a = {1 |-> {[] |-> 2}, 2 |-> (dom({pi,ff,p|((pi : seq(INTEGER) & ff : INTEGER) & p : seq(INTEGER)) & (p |-> ff : [a(1)](1) & pi = 1 -> p)}) \/ {[] |-> 1})}
793 % test 1552 is currently skipped
794 % TO DO: think whether there are other deterministic computations that can be done in b_compile: prj1,prj2, record-field access ? this would ensure that closures,... can be computed earlier
795 lookup_result(VAR,_,_,_WF) :- var(VAR),!,fail.
796 lookup_result([(HFrom,HTo)|T],X,Result,WF) :-
797 equality_objects_wf(HFrom,X,PredRes,WF), %print(compare(PredRes,HFrom,X)),nl,
798 nonvar(PredRes), % only proceed if we have enough information to determine the result of the comparison
799 (PredRes = pred_true -> Result = HTo % we have found the value; we assume there is no other value later
800 % TO DO: if find_abort_values=true: look later in the list if for all other HFrom PredRes=pred_false
801 ; lookup_result(T,X,Result,WF)).
802
803 % get_comprehension_set(b(SET,_,_),ID,PRED) :- get_comprehension_set_aux(SET,ID,PRED).
804 % get_comprehension_set_aux(comprehension_set([TID],PRED),ID,PRED) :-
805 % get_texpr_id(TID,ID).
806 % get_comprehension_set_aux(value(V),ID,PRED) :- nonvar(V), V = closure([ID],_,PRED).
807
808
809
810
811 quick_test_membership1(b(value(VA),_,_),VB,Result) :-
812 ? quick_test_membership_aux(VB,VA,Result).
813 quick_test_membership_aux(VAR,_,_) :- var(VAR),!,fail.
814 quick_test_membership_aux([],_,pred_false).
815 quick_test_membership_aux(avl_set(AVL),X,Result) :-
816 custom_explicit_sets:quick_test_avl_membership(AVL,X,Result). % we could also check that in case X is not ground but partially instantiated, whether there is a possible match in AVL (if not Result = pred_false)
817 quick_test_membership_aux(global_set(GS),X,Result) :- nonvar(X), X=int(IX), nonvar(IX),
818 custom_explicit_sets:membership_global_set(GS,X,R,_WF),
819 nonvar(R), Result=R.
820 quick_test_membership_aux(closure(P,T,B),X,Result) :- nonvar(X), X=int(IX), nonvar(IX),
821 custom_explicit_sets:is_interval_closure(P,T,B,LOW,UP), number(LOW),number(UP),
822 kernel_equality:in_nat_range_test(X,int(LOW),int(UP),R),
823 nonvar(R), Result=R.
824 quick_test_membership_aux(closure(P,T,B),X,Result) :- X==[], % check {} : POW(_) / FIN(_) and {} : POW1(_) / FIN1(_)
825 custom_explicit_sets:is_powerset_closure(closure(P,T,B),Kind,_),
826 (contains_empty_set(Kind) -> Result = pred_true ; Result=pred_false).
827
828 contains_empty_set(pow).
829 contains_empty_set(fin).
830
831 convert_pred_res(pred_false,falsity).
832 convert_pred_res(pred_true,truth).
833 convert_neg_pred_res(pred_true,falsity).
834 convert_neg_pred_res(pred_false,truth).
835
836 generate_equality(b(A,_,_),b(B,_,_),Res) :-
837 ( generate_equality_aux(A,B,Res) ;
838 generate_equality_aux(B,A,Res) ),
839 !.
840 generate_equality(A,B,equal(A,B)).
841
842 generate_equality_aux(convert_bool(AA),value(PT),Res) :-
843 PT==pred_true,
844 get_texpr_expr(AA,TA),
845 !,
846 %print(simplify_bool(AA,PT)),nl,
847 Res = TA.
848 generate_equality_aux(convert_bool(AA),value(PF),Res) :-
849 PF==pred_false,!,
850 %print(simplify_bool(AA,PF)),nl,
851 Res = negation(AA).
852
853 known_value(X,FullyKnown) :- (known_value(X) -> FullyKnown=true ; FullyKnown=false).
854 known_value(X) :- nonvar(X), known_value2(X).
855 known_value2(global_set(GS)) :- nonvar(GS).
856 known_value2(freetype(GS)) :- nonvar(GS).
857 known_value2(closure(P,T,B)) :- known_closure(P,T,B).
858 %Note: for other closures: they still may have to be computed; some of the computations in wd_and_efficient could be expensive for closures
859 known_value2(avl_set(_)). % already fully normalised
860 known_value2((X,Y)) :- known_value(X),known_value(Y).
861 known_value2(fd(A,B)) :- number(A),atomic(B).
862 known_value2(int(N)) :- number(N).
863 known_value2([]).
864 known_value2(pred_true).
865 known_value2(pred_false).
866 known_value2(string(S)) :- atomic(S).
867 known_value2([H|T]) :- known_value(H), known_value(T).
868 %known_value2(record(Fields)) :- known_fields(Fields).
869 known_value2(rec(Fields)) :- known_fields(Fields).
870
871
872 known_closure(P,T,B) :- custom_explicit_sets:is_interval_closure(P,T,B,Low,Up), !,
873 number(Low), number(Up),
874 Up < Low+1000.
875 known_closure(P,T,B) :-
876 is_cartesian_product_closure(closure(P,T,B),A1,A2),
877 !,% we could call is_cartesian_product_closure_aux(P,T,B,A1,A2)
878 known_value(A1), known_value(A2).
879
880 known_fields(X) :- var(X),!,fail.
881 known_fields([]).
882 known_fields([field(N,V)|T]) :- ground(N),known_value(V),known_fields(T).
883
884 %b_evaluate1(TExpr,Parameters,LS,S,ResultTExpr,FullyKnown) :-
885
886 check_is_id_list([],[]).
887 check_is_id_list([H|T],Res) :-
888 (H=b(identifier(_),_,_)
889 -> add_internal_error('Typed id list as argument: ',check_is_id_list([H|T],Res)), % use get_texpr_ids or maplist(def_get_texpr_id,P,PIDs)
890 maplist(def_get_texpr_id,[H|T],Res)
891 ; Res=[H|T]).
892
893 :- use_module(kernel_frozen_info,[kfi_domain/2]).
894
895 :- use_module(custom_explicit_sets,[construct_interval_closure/3]).
896 % try and evaluate domain of a list (avl_set already dealt with separately)
897 %evaluate_domain(X,_) :- print(dom(X)),nl,fail.
898 evaluate_domain(sequence_extension(L),Domain) :- length(L,Len),
899 % this will prevent computing range of sequence extension: can hide WD issues ! TO DO: check wd info and/or preference
900 construct_interval_closure(1,Len,Domain).
901 % TO DO: set_extension when possible ?
902 evaluate_domain(value(L),Domain) :-
903 get_domain(L,Domain).
904
905 get_domain(V,Dom) :- var(V),!,kfi_domain(V,Dom). % try infer domain from attached co-routines
906 get_domain([],[]).
907 get_domain([V|VT],Result) :- nonvar(V), V=(D,_),
908 known_value(D),get_list_domain(VT,DT),
909 sort([D|DT],Result).
910 % we could also do this:
911 %get_domain(closure(Par,Typ,Body),Result) :-
912 % is_lambda_value_domain_closure(Par,Typ,Body, DomainValue,Expr), check_wd(Expr),
913 % Result=DomainValue.
914 get_list_domain(V,_) :- var(V),!,fail.
915 get_list_domain([],[]).
916 get_list_domain([V|VT],[D|DT]) :- nonvar(V), V=(D,_),
917 known_value(D),get_list_domain(VT,DT).
918
919
920 :- use_module(kernel_frozen_info,[kfi_range/2]).
921
922 % try and evaluate range of a list (avl_set already dealt with separately)
923 evaluate_range(b(value(L),_T,_),Range) :-
924 get_range(L,Range).
925 get_range(V,Dom) :- var(V),!,kfi_range(V,Dom). % try infer range from attached co-routines
926 get_range([],[]).
927 get_range([V|VT],Result) :- nonvar(V), V=(_,D),
928 known_value(D),
929 get_list_range(VT,DT),
930 sort([D|DT],Result).
931
932 get_list_range(V,_) :- var(V),!,fail.
933 get_list_range([],[]).
934 get_list_range([V|VT],[D|DT]) :-
935 nonvar(V), V=(_,D),
936 known_value(D),
937 get_list_range(VT,DT).
938
939 create_equality_for_let(LHS,RHS,Conj) :-
940 maplist(create_eq,LHS,RHS,CL),
941 conjunct_predicates(CL,Conj).
942 create_eq(Id,Expr,TPred) :- safe_create_texpr(equal(Id,Expr),pred,TPred).
943
944 % split formal operation call parameters into those which clash and those that do not:
945 split_formal_parameters([],[],_,[],[],[],[]).
946 split_formal_parameters([Formal1|FormalT],[Val1|VT],LocalKnownParas,Fresh,FV,Clash,CV) :-
947 (id_clash(LocalKnownParas,Formal1)
948 -> Fresh = FreshT, FV=FVT, Clash = [Formal1|ClashT], CV = [Val1|CVT]
949 ; Fresh = [Formal1|FreshT], FV = [Val1|FVT], Clash = ClashT, CV = CVT
950 ), split_formal_parameters(FormalT,VT,LocalKnownParas,FreshT,FVT,ClashT,CVT).
951
952 :- use_module(gensym,[gensym/2]).
953 create_fresh_id(b(identifier(_),T,I),b(identifier(FRESHID),T,I)) :-
954 gensym('__COMPILED_ID__',FRESHID).
955
956 :- use_module(bsyntaxtree, [get_texpr_pos/2,same_id/3]).
957 % compute which assignments are really necessary, remove skip assignments x := x
958 simplify_assignment([],[],[],[]).
959 simplify_assignment([ID1|T1],[ID2|T2],Res1,Res2) :-
960 (same_id(ID1,ID2,_) -> Res1=TR1, Res2=TR2 ; Res1=[ID1|TR1], Res2=[ID2|TR2]),
961 simplify_assignment(T1,T2,TR1,TR2).