| 1 | | % (c) 2009-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(b_compiler,[b_compile/6, b_optimize/6, b_compile_closure/2]). |
| 7 | | |
| 8 | | :- use_module(library(lists)). |
| 9 | | |
| 10 | | :- use_module(self_check). |
| 11 | | :- use_module(bsyntaxtree). |
| 12 | | :- use_module(error_manager). |
| 13 | | :- use_module(debug,[debug_format/3]). |
| 14 | | :- use_module(btypechecker,[fasttype/2]). |
| 15 | | :- use_module(bmachine,[b_get_machine_operation_for_animation/6]). |
| 16 | | :- use_module(b_interpreter). |
| 17 | | :- use_module(custom_explicit_sets). |
| 18 | | :- use_module(kernel_waitflags,[add_error_wf/5, add_internal_error_wf/5]). |
| 19 | | %:- use_module(bmachine,[b_operation_reads_output_variables/3]). |
| 20 | | :- use_module(probsrc(performance_messages),[performance_monitoring_on/0,perfmessage/3]). |
| 21 | | |
| 22 | | :- use_module(module_information,[module_info/2]). |
| 23 | | :- module_info(group,interpreter). |
| 24 | | :- module_info(description,'This module compiles set comprehensions into closures; making them independent of the state of the B machine.'). |
| 25 | | |
| 26 | | /* compile boolean expression into a closure where the local state and the global |
| 27 | | state has been incorporated, but any parameter is left in the closure */ |
| 28 | | |
| 29 | | :- public test_bexpr/3, test_bexpr2/3. |
| 30 | | test_bexpr(Expr,[bind(cc,int(1)),bind(nn,int(2))], [bind(db,[(int(1),int(2))])]) :- |
| 31 | | fasttype( +conjunct( +conjunct( +member( global('Name')<<identifier(nn), +identifier('Name')), |
| 32 | | +member( global('Code')<<identifier(cc), +identifier('Code'))), |
| 33 | | +not_member( global('Name')<<identifier(nn), |
| 34 | | +domain(set(couple(global('Name'),global('Code')))<<identifier(db)))), Expr). |
| 35 | | |
| 36 | | test_bexpr2(Expr,[],[]) :- |
| 37 | | fasttype( +implication( +equal( seq(any)<<identifier(ss), +empty_sequence), |
| 38 | | +equal( set(any)<<identifier(res), +empty_set)), Expr). |
| 39 | | |
| 40 | | |
| 41 | | |
| 42 | | b_compile_closure(closure(P,T,Body),Res) :- b_compiler:b_compile(Body,P,[],[],CBody),!, Res=closure(P,T,CBody). |
| 43 | | b_compile_closure(C,C). |
| 44 | | |
| 45 | | |
| 46 | | % difference with b_compile: the states LS, S will not be thrown away by the interpreter |
| 47 | | % thus: we do not have to compile all accesses, in particular lazy lookups ! |
| 48 | | %b_optimize(TExpr,Parameters,_LS,_S,NTExpr,_WF) :- TExpr=b(_,_,Infos), member(already_optimized,Infos), |
| 49 | | % !, NTExpr=TExpr. |
| 50 | | b_optimize(TExpr,Parameters,LS,S,NTExpr,WF) :- %print('OPTIMIZE: '),translate:print_bexpr(TExpr),nl, trace, |
| 51 | | append(LS,[bind('$optimize_do_not_force_lazy_lookups',pred_true)],NewLS), |
| 52 | ? | b_compile(TExpr,Parameters,NewLS,S,NTExpr,WF). |
| 53 | | %bsyntaxtree:add_texpr_info_if_new(NTExpr,already_optimized,ResTExpr). |
| 54 | | |
| 55 | | b_compile(TExpr,Parameters,NewLS,S,NTExpr) :- |
| 56 | ? | b_compile(TExpr,Parameters,NewLS,S,NTExpr,no_wf_available). % for unit tests |
| 57 | | |
| 58 | | :- assert_must_succeed(( b_compiler:test_bexpr(E,L,S), |
| 59 | | b_compiler:b_compile(E,[nn],L,S,_R) )). |
| 60 | | :- assert_must_succeed(( b_compiler:test_bexpr2(E,L,S), |
| 61 | | b_compiler:b_compile(E,[ss,res],L,S,_R) )). |
| 62 | | :- assert_must_succeed(( b_compiler:b_compile(b(greater(b(value(int(2)),integer,[]), |
| 63 | | b(value(int(1)),integer,[])),pred,[]),[],[],[],Res), |
| 64 | | check_eq(Res,b(truth,pred,_)) )). |
| 65 | | :- assert_must_succeed(( b_compiler:b_compile(b(greater(b(value(int(2)),integer,[]), |
| 66 | | b(value(int(3)),integer,[])),pred,[]),[],[],[],Res), |
| 67 | | check_eq(Res,b(falsity,pred,_)) )). |
| 68 | | :- assert_must_succeed(( E = b(greater(b(value(int(2)),integer,[]), |
| 69 | | b(value(int(_)),integer,[])),pred,[]), |
| 70 | | b_compiler:b_compile(E,[],[],[],Res), |
| 71 | | check_eq(Res,E) )). |
| 72 | | :- assert_must_succeed(( E = b(greater(b(value(int(2)),integer,[]), |
| 73 | | b(value(_),integer,[])),pred,[]), |
| 74 | | b_compiler:b_compile(E,[],[],[],Res), |
| 75 | | check_eq(Res,E) )). |
| 76 | | :- assert_must_succeed(( E = b(greater(b(value(int(2)),integer,[]), |
| 77 | | b(identifier(x),integer,[])),pred,[]), |
| 78 | | b_compiler:b_compile(E,[],[bind(x,int(1))],[],Res), |
| 79 | | check_eq(Res,b(truth,pred,_)) )). |
| 80 | | :- assert_must_succeed(( E = b(greater(b(value(int(2)),integer,[]), |
| 81 | | b(identifier(x),integer,[])),pred,[]), |
| 82 | | b_compiler:b_compile(E,[],[bind(x,int(3))],[],Res), |
| 83 | | check_eq(Res,b(falsity,pred,_)) )). |
| 84 | | |
| 85 | | %:- assert_pre(b_compiler:b_compile_boolean_expression(E,Parameters,LS,S,_), |
| 86 | | % (type_check(E,boolean_expression),type_check(Parameters,list(variable_id)), |
| 87 | | % type_check(LS,store),type_check(S,store))). |
| 88 | | %:- assert_post(b_compiler:b_compile_boolean_expression(_,_,_,_,E), type_check(E,boolean_expression)). |
| 89 | | |
| 90 | | /* probably not worthwhile: |
| 91 | | b_compile(TExpr,Parameters,LS,S,NTExpr) :- get_texpr_info(TExpr,Info), |
| 92 | | (memberchk(compiled(Parameters),Info) -> NTExpr = TExpr ,print(already_compiled(Parameters)),nl, translate:print_bexpr(TExpr),nl |
| 93 | | ; b_compile0(TExpr,Parameters,LS,S,b(E,T,I)), translate:print(compiling(Parameters)),nl, translate:print_bexpr(TExpr),nl, |
| 94 | | NTExpr = b(E,T,[compiled(Parameters)|I])). |
| 95 | | */ |
| 96 | | :- use_module(closures,[get_recursive_identifier_of_closure_body/2]). |
| 97 | | b_compile(TExpr,Parameters,LS,S,NTExpr,WF) :- |
| 98 | | check_is_id_list(Parameters,Parameters0), |
| 99 | ? | (get_recursive_identifier_of_closure_body(TExpr,TRID), |
| 100 | | def_get_texpr_id(TRID,RID), nonmember(bind(RID,_),LS) |
| 101 | | -> Parameters1=[RID|Parameters0] % add recursive ID virtually to parameters to avoid error messages |
| 102 | | ; Parameters1=Parameters0), |
| 103 | | % print('compile : '),translate:print_bexpr(TExpr),nl, statistics(runtime,[Start,_]),%% |
| 104 | | sort(Parameters1,Parameters2), |
| 105 | ? | if(b_compile1(TExpr,Parameters2,LS,S,NTExpr0,eval,FullyKnown,WF), |
| 106 | | (FullyKnown=true |
| 107 | | -> copy_pos_infos(TExpr,NTExpr0,NTExpr) |
| 108 | | % ensure position info is not deleted if full expression compiled away, see PROB-412 (test 1677) |
| 109 | | ; NTExpr=NTExpr0), |
| 110 | | (add_internal_error_wf(b_compiler,'Compilation failed: ',TExpr,TExpr,WF), |
| 111 | | %b_compile1(TExpr,Parameters1,LS,S,NTExpr0,eval,_FullyKnown,WF), |
| 112 | | NTExpr = TExpr) |
| 113 | | ). |
| 114 | | %, bsyntaxtree:check_ast(NTExpr). |
| 115 | | %, check_infos(TExpr,NTExpr). |
| 116 | | %, 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 |
| 117 | | |
| 118 | | /* |
| 119 | | check_infos(Old,New) :- bsyntaxtree:get_texpr_info(Old,IO), |
| 120 | | bsyntaxtree:get_texpr_info(New,IN), |
| 121 | | member(X,IO), \+ member(X,IN), |
| 122 | | bsyntaxtree:important_info(X), |
| 123 | | print(check_infos(Old,New)),nl, |
| 124 | | print('Not copied: '), print(X),fail. |
| 125 | | check_infos(_,_). */ |
| 126 | | |
| 127 | | :- use_module(bsyntaxtree,[always_well_defined/1]). |
| 128 | | :- use_module(translate,[translate_bexpression_with_limit/2]). |
| 129 | | %:- use_module(hit_profiler,[add_profile_hit/1]). |
| 130 | | |
| 131 | | % Eval=eval means the expression will be needed in a successful branch and we can pre-compute more aggressively |
| 132 | | % Eval=false means the expression may not be needed (e.g., in a disjunction) and only perform efficient precomputations |
| 133 | | b_compile1(TExpr,Parameters,LS,S,ResultTExpr,Eval,FullyKnown1,WF) :- |
| 134 | | TExpr = b(Expr,Type,Infos), |
| 135 | | NTExpr = b(NewUntypedExpr,Type,NewInfos), |
| 136 | | %remove_bt(TExpr,Expr,NewUntypedExpr,NTExpr), % remove top-level Type Information |
| 137 | | %hit_profiler:add_profile_hit(Expr), |
| 138 | | %functor(Expr,E1,N1), %print(start_compile(E1/N1,Eval,FullyKnown1)),nl, |
| 139 | ? | b_compile1_infos(Expr,Type,Infos,Parameters,LS,S,NewUntypedExpr,NewInfos,Eval,FullyKnown,WF), |
| 140 | | %functor(NewUntypedExpr,E2,N2), |
| 141 | | %format(' compiled ~w/~w -> ~w/~w : ',[E1,N1,E2,N2]),translate:print_bexpr_or_subst(NTExpr),nl, |
| 142 | | %format(' fully=~w, eval=~w~n',[FullyKnown,Eval]), |
| 143 | | (NTExpr = b(value(_),_,_) |
| 144 | | -> FullyKnown1=FullyKnown, ResultTExpr=NTExpr |
| 145 | | ; FullyKnown=true, evaluate_this(Eval,NewUntypedExpr,Type,NewInfos) |
| 146 | | -> % print('eval : '),translate:print_bexpr(NTExpr),nl, % |
| 147 | | (nonvar(NewUntypedExpr), |
| 148 | | % if( would be more prudent !?, also: we used to call b_compute_expression_nowf |
| 149 | ? | b_interpreter:b_compute_expression(NTExpr,LS,S,ResultValue,WF) |
| 150 | | -> %print(result(ResultValue)),nl, |
| 151 | | %remove_bt(TExpr,Expr,value(ResultValue),ResultTExpr) |
| 152 | | get_texpr_type(TExpr,TT),ResultTExpr = b(value(ResultValue),TT,[]), |
| 153 | | FullyKnown1 = FullyKnown |
| 154 | | %, print(compiled_value(ResultTExpr)),nl |
| 155 | | ; add_internal_error_wf(b_compiler,'Undefined value marked for evaluation:',NTExpr,Infos,WF), |
| 156 | | %trace, b_interpreter:b_compute_expression(NTExpr,LS,S,ResultValue,WF), |
| 157 | | ResultTExpr=NTExpr, FullyKnown1=false |
| 158 | | ) |
| 159 | | ; % ((FullyKnown=true, NTExpr\=b(value(_),_,_)) -> format('not eval: ~w (~w)~n',[NTExpr,Eval]) ; true), |
| 160 | | ResultTExpr=NTExpr, FullyKnown1=false |
| 161 | | ). |
| 162 | | |
| 163 | | |
| 164 | | :- use_module(library(ordsets),[ord_member/2, ord_union/3]). |
| 165 | | :- use_module(bsyntaxtree,[create_exists_or_let_predicate/3]). |
| 166 | | :- use_module(tools_lists,[delete_first/3]). |
| 167 | | add_parameters(SortedIds,NewIds,NewSortedIds) :- |
| 168 | | sort(NewIds,SNew), |
| 169 | | ord_union(SortedIds,SNew,NewSortedIds). |
| 170 | | |
| 171 | | b_compile1_infos(exists(ExistsPara,Pred),_,OldInfos,Parameters,LS,S,NExpr,NewInfos,Eval,FullyKnown,WF) :- !, |
| 172 | | FullyKnown=false, % predicates never automatically evaluated in b_compile1 |
| 173 | | get_texpr_ids(ExistsPara,AtomicIds), |
| 174 | | add_parameters(Parameters,AtomicIds,NParameters), |
| 175 | ? | b_compile1(Pred,NParameters,LS,S,NPred,Eval,_FullyKnown1,WF), |
| 176 | | (is_falsity(NPred) -> NExpr = falsity, NewInfos = OldInfos |
| 177 | | ; is_truth(NPred) -> NExpr = truth, NewInfos = OldInfos |
| 178 | | %; Pred==NPred, write(unchanged(Parameters)),nl, member(used_ids(Old),OldInfos), print(used(Old)),nl,nl,fail |
| 179 | | ; create_exists_or_let_predicate(ExistsPara,NPred,b(NExpr,pred,NI)), |
| 180 | | %print('COMPILED EXISTS: '), translate:print_bexpr(b(NExpr,pred,NI)),nl, |
| 181 | | (delete_first(OldInfos,used_ids(_),I1), |
| 182 | ? | member(used_ids(NewUsedIds),NI) -> NewInfos = [used_ids(NewUsedIds)|I1] |
| 183 | | ; %nl,print(missing_used_ids(OldInfos,NI)),nl, % can happen when we construt a let_predicate above |
| 184 | | update_infos(NExpr,OldInfos,Parameters,NewInfos)) |
| 185 | | ). |
| 186 | | b_compile1_infos(identifier(Id),Type,OldInfos,Parameters,LS,S,NExpr,NewInfos,_Eval,FullyKnown,WF) :- !, |
| 187 | | ( ord_member(Id,Parameters) -> |
| 188 | | NExpr = identifier(Id), FullyKnown=false, NewInfos = OldInfos |
| 189 | | ; Id=op(_) -> |
| 190 | | NExpr = identifier(Id), FullyKnown=false, NewInfos = OldInfos |
| 191 | | ; b_interpreter:lookup_value_in_store_and_global_sets_wf(Id,Type,LS,S,Value,OldInfos,WF) -> |
| 192 | | NExpr = value(Value), (known_value(Value) -> FullyKnown=true ; FullyKnown=false), |
| 193 | | NewInfos = [was_identifier(Id)|OldInfos] |
| 194 | | ; add_internal_error_wf(b_compiler,'Compilation of identifier failed: ',Id,OldInfos,WF), |
| 195 | | NExpr = identifier(Id), FullyKnown=false, NewInfos = OldInfos |
| 196 | | ). |
| 197 | | b_compile1_infos(Expr,_,OldInfos,_Parameters,_LS,_S,NewUntypedExpr,NewInfos,_Eval,FullyKnown,_WF) :- |
| 198 | ? | b_ast_cleanup:is_integer_set(Expr,_Set),!, |
| 199 | | NewUntypedExpr=Expr, NewInfos=OldInfos,FullyKnown=true. |
| 200 | | b_compile1_infos(operation_call_in_expr(Operation,OpCallParas),_Type,OldInfos,Parameters,LS,S, |
| 201 | | Compiled,NewInfos,Eval,FullyKnown,WF) :- !, |
| 202 | | def_get_texpr_id(Operation,op(OperationName)), |
| 203 | | FullyKnown = false, |
| 204 | | b_compile_l(OpCallParas,Parameters,LS,S,OpCallParaValues,Eval,_,WF), |
| 205 | | (b_get_operation_normalized_read_write_info(OperationName,ReadVars,Modified) -> true |
| 206 | | ; member(reads(ReadVars),OldInfos), member(modifies(Modified),OldInfos) |
| 207 | | -> add_message(b_compiler,'Unregistered operation in expression: ',OperationName) |
| 208 | | % should not happen; but proceed with the locally stored reads/writes info |
| 209 | | ; add_error_wf(b_compiler,'Cannot obtain read/write info for operation:',OperationName,OldInfos,WF), |
| 210 | | write(OldInfos),nl,nl, |
| 211 | | ReadVars=[], Modified=[] |
| 212 | | ), |
| 213 | | %exclude(operation_identifier,Read,ReadVars), % Read used to contain operations used via operation_call_in_expr; TO DO: check if this is ok in other places of source code of ProB; see test 1957 |
| 214 | | (Modified=[] -> true |
| 215 | | ; add_error_wf(b_compiler,'Calling operation that modifies state in expression:',OperationName,OldInfos,WF)), |
| 216 | | % print(compile_call_op(OperationName,ReadVars,Modified,OpCallParaValues)),nl, |
| 217 | | (ReadVars=[] |
| 218 | | -> Compiled = operation_call_in_expr(Operation,OpCallParaValues), |
| 219 | | NewInfos = OldInfos |
| 220 | | ; maplist(create_value_for_read_variable(LS,S,WF),ReadVars,TRead,TValues), |
| 221 | | safe_create_texpr(let_expression_global(TRead,TValues, |
| 222 | | b(operation_call_in_expr(Operation,OpCallParaValues),any,OldInfos)),any,[generated_by_b_compiler],New), |
| 223 | | New = b(Compiled,_,NewInfos) |
| 224 | | %NewInfos = [generated_by_b_compiler], |
| 225 | | %Compiled = let_expression_global(TRead,TValues, |
| 226 | | % b(operation_call_in_expr(Operation,OpCallParaValues),any,OldInfos)) |
| 227 | | ). |
| 228 | | b_compile1_infos(kodkod(Id,Identifiers),_,OldInfos,Parameters,LS,S,NExpr,NewInfos,_Eval,FullyKnown,WF) :- !, |
| 229 | | FullyKnown=false, NewInfos=OldInfos, |
| 230 | | exclude(is_parameter(Parameters),Identifiers,IdsToCompile), |
| 231 | | (IdsToCompile=[] |
| 232 | | -> NExpr = kodkod(Id,Identifiers) |
| 233 | | ; maplist(precompile_id(LS,S,WF),IdsToCompile,Values), |
| 234 | | % as we cannot inspect kodkod problem: wrap it into a let with the values stored: |
| 235 | | NExpr = let_predicate(IdsToCompile,Values,b(kodkod(Id,Identifiers),pred,OldInfos)) |
| 236 | | ). |
| 237 | | b_compile1_infos(Expr,_,OldInfos,Parameters,LS,S,NewUntypedExpr,NewInfos,Eval,FullyKnown,WF) :- |
| 238 | ? | b_compile2(Expr,Parameters,LS,S,NewUntypedExpr,Eval,FullyKnown,WF), |
| 239 | | update_infos(NewUntypedExpr,OldInfos,Parameters,NewInfos). |
| 240 | | |
| 241 | | |
| 242 | | is_parameter(Parameters,b(identifier(Id),_,_)) :- ord_member(Id,Parameters). |
| 243 | | |
| 244 | | precompile_id(LS,S,WF,b(identifier(Id),Type,Info),b(value(Value),Type,[])) :- |
| 245 | | b_interpreter:lookup_value_in_store_and_global_sets_wf(Id,Type,LS,S,Value,Info,WF). |
| 246 | | % was_identifier is aded in b_compile1_infos |
| 247 | | |
| 248 | | :- use_module(bmachine,[b_get_operation_normalized_read_write_info/3]). |
| 249 | | |
| 250 | | %operation_identifier(op(_)). |
| 251 | | create_value_for_read_variable(LS,S,WF,Variable,TVariable,TValue) :- |
| 252 | | b_interpreter:lookup_value_in_store_and_global_sets_wf(Variable,_Type,LS,S,Value,unknown,WF),!, |
| 253 | | % TO DO: try and find type? |
| 254 | | TVariable = b(identifier(Variable),any,[]), |
| 255 | | TValue = b(value(Value),any,[]). |
| 256 | | create_value_for_read_variable(_LS,_S,WF,Variable,TVariable,b(value(term(undefined)),any,[])) :- |
| 257 | | TVariable = b(identifier(Variable),any,[]), |
| 258 | | add_internal_error_wf(b_compiler,'Cannot find variable (read) while compiling operation:',Variable,unknown,WF), |
| 259 | | fail. |
| 260 | | |
| 261 | | :- use_module(library(ordsets)). |
| 262 | | update_infos(forall(EParas,LHS,RHS),Infos,Parameters,NewInfos) :- |
| 263 | | % forall also has used_ids field as it may call exists in negative context |
| 264 | | conjunct_predicates([LHS,RHS],Cond), |
| 265 | | update_infos_aux(EParas,Cond,Infos,Parameters,NewInfos),!. |
| 266 | | update_infos(exists(EParas,Cond),Infos,Parameters,NewInfos) :- % we create_exists_or_let_predicate above, but other transformations may generate an exists below: |
| 267 | | update_infos_aux(EParas,Cond,Infos,Parameters,NewInfos),!. |
| 268 | | update_infos(BOP,Infos,_,NewInfos) :- bsyntaxtree:syntaxelement(BOP, [A,B],[], [], [], _), |
| 269 | | wd_and_efficient(BOP), % should not generate WD errors itself |
| 270 | ? | (select(contains_wd_condition,Infos,NewInfos) % there is a WD condition attached |
| 271 | | -> fast_check_wd(A), |
| 272 | | fast_check_wd(B) |
| 273 | | ), |
| 274 | | %print(removing_wd_condition(BOP)),nl, |
| 275 | | !. |
| 276 | | update_infos(_,I,_,I). |
| 277 | | |
| 278 | | update_infos_aux(EParas,Cond,Infos,Parameters,NewInfos) :- |
| 279 | | select_used_ids(UsedIds,Infos,I1,EParas,Cond), |
| 280 | | UsedIds \= [],!, |
| 281 | | % remove those used identifiers which will be compiled into the predicate |
| 282 | | sort(Parameters,SParas), |
| 283 | | ord_intersection(UsedIds,SParas,NewUsedIds), |
| 284 | | %print(update(Parameters,UsedIds,I1,new(NewUsedIds))),nl, |
| 285 | | NewInfos = [used_ids(NewUsedIds)|I1]. |
| 286 | | |
| 287 | | :- use_module(bsyntaxtree,[find_identifier_uses/3]). |
| 288 | ? | select_used_ids(UsedIds,Infos,I1,_,_) :- select(used_ids(UsedIds),Infos,I1),!. |
| 289 | | % check_used_ids_info(Parameters,Condition,UsedIds,b_compiler) |
| 290 | | select_used_ids(UsedIds,Infos,Infos,_Parameters,Condition) :- |
| 291 | | %add_error(bcompiler,'Expected information of used identifiers in exists operation information : ',Parameters:Infos), %% missing info can happen due to simplifcation rules below ! |
| 292 | | find_identifier_uses(Condition, [], UsedIds). % ,print(used(UsedIds,in_exist(Parameters))),nl. |
| 293 | | % TO DO: avoid re-computing used-ids; we should refactor b_compile2 to return new Info field |
| 294 | | |
| 295 | | |
| 296 | | |
| 297 | | evaluate_this(eval,X,Type,Info) :- !, worth_it_type(Type,X,Info). |
| 298 | | evaluate_this(_,function(A,B),Type,Info) :- !, |
| 299 | | A=b(value(VA),_,_), nonvar(VA), VA=avl_set(_), |
| 300 | | B=b(value(_),_,_), |
| 301 | | worth_it_type(Type,function(A,B),Info). % will check well-definedness |
| 302 | | evaluate_this(_,X,_Type,_Info) :- wd_and_efficient(X). |
| 303 | | |
| 304 | | |
| 305 | | % things which are very quick to compute |
| 306 | | wd_and_efficient(sequence_extension(_)) :- !. |
| 307 | | wd_and_efficient(set_extension(_)) :- !. |
| 308 | | wd_and_efficient(integer_set(_)) :- !. % will be converted into value(global_set(_)) |
| 309 | | %% wd_and_efficient(value(_)) :- !. % is already computed |
| 310 | | % the following will reduce the size of the representation; usually a good thing; |
| 311 | | % we assume only avl_sets apprear here; inner set comprehensions are never computed into symbolic form by b_compile (see known_value below): |
| 312 | | %wd_and_efficient(identity(_)) :- !. |
| 313 | | wd_and_efficient(range(_)) :- !. |
| 314 | | wd_and_efficient(domain(_)) :- !. |
| 315 | | wd_and_efficient(domain_restriction(_,_)) :- !. |
| 316 | | wd_and_efficient(domain_subtraction(_,_)) :- !. |
| 317 | | wd_and_efficient(range_restriction(_,_)) :- !. |
| 318 | | wd_and_efficient(range_subtraction(_,_)) :- !. |
| 319 | | wd_and_efficient(intersection(_,_)) :- !. |
| 320 | | wd_and_efficient(set_subtraction(_,_)) :- !. |
| 321 | | wd_and_efficient(image(_,_)) :- !. |
| 322 | | wd_and_efficient(reverse(_)) :- !. % added for rgen_rgen_Worst_Case_Stopping_distance_NCT_trm13 |
| 323 | | % reverse has n.log(n) complexity, but is always wd and can be beneficial |
| 324 | | wd_and_efficient(union(A,B)) :- finite_set(A), finite_set(B), !. % has complexity n |
| 325 | | % usually the union of two avl_sets will be smaller than keeping them separate, what about intervals? |
| 326 | | wd_and_efficient(interval(_,_)) :- !. % ditto |
| 327 | | wd_and_efficient(card(S)) :- !, % added for rgen_rgen_Worst_Case_Stopping_distance_NCT_trm13 |
| 328 | | (finite_set(S) -> true % is wd for finite set; has currently linear complexity but reduces size of closure |
| 329 | | ; is_interval(S) -> true). % card is simple to compute |
| 330 | | wd_and_efficient(min(S)) :- !, % logarithmic for avl_set, see test 1338 |
| 331 | | finite_non_empty_set(S). |
| 332 | | wd_and_efficient(max(S)) :- !, % logarithmic for avl_set |
| 333 | | finite_non_empty_set(S). |
| 334 | | wd_and_efficient(string_set) :- !. |
| 335 | | % some other efficient operators: |
| 336 | | % external_function_call CHOOSE (test 1338) ? |
| 337 | | % first, last, ... need to ensure we have sequence |
| 338 | | wd_and_efficient(X) :- worth_it_int(X),!. |
| 339 | | wd_and_efficient(X) :- worth_it_other(X). |
| 340 | | |
| 341 | | is_interval(b(value(V),set(_),_)) :- nonvar(V), V=closure(P,T,B), |
| 342 | | is_fixed_interval(P,T,B,_,_). |
| 343 | | |
| 344 | | finite_set(b(value(V),set(_),_)) :- nonvar(V), finite_set_aux(V). |
| 345 | | finite_set_aux([]). |
| 346 | | finite_set_aux(avl_set(_)). |
| 347 | | finite_non_empty_set(b(value(V),set(_),_)) :- nonvar(V), V=avl_set(_). |
| 348 | | |
| 349 | | fast_check_wd(b(E,_,Infos)) :- |
| 350 | | (nonmember(contains_wd_condition,Infos) -> true |
| 351 | | ; nonvar(E), E=value(_)). |
| 352 | | |
| 353 | | check_wd(NTExpr) :- bsyntaxtree:always_well_defined(NTExpr). % ,print(wd(NTExpr)),nl. |
| 354 | | %(bsyntaxtree:always_well_defined(NTExpr) -> true ; print(not_guaranteed_wd(NTExpr)),nl). |
| 355 | | |
| 356 | | % (worth_it_type(Type,X,Info) -> true ; X=value(_) -> true ; print(not_evaluating(X)),nl,fail). |
| 357 | | worth_it_type(integer,X,Info) :- worth_it_int_wd(X),!, check_wd(b(X,integer,Info)). |
| 358 | | worth_it_type(T,function(A,B),Info) :- !, |
| 359 | | (check_wd(b(function(A,B),T,Info)) -> true |
| 360 | | ; fail). %print('not_precompiling_function '),translate:print_bexpr(A), print(' @ '), translate:print_bexpr(B),nl,fail). |
| 361 | | worth_it_type(integer,X,_) :- worth_it_int(X),!. |
| 362 | | worth_it_type(T,X,Info) :- worth_it_wd(X),!, check_wd(b(X,T,Info)). |
| 363 | ? | worth_it_type(set(_),X,_) :- worth_it_set(X),!. |
| 364 | | worth_it_type(seq(_),X,_) :- worth_it_set(X),!. |
| 365 | | worth_it_type(_,X,_) :- worth_it_other(X). |
| 366 | | |
| 367 | | % TO DO: we should use the predicate has_wd_condition from b_ast_cleanup |
| 368 | | |
| 369 | | % integer operations that could generate WD-errors |
| 370 | | worth_it_int_wd(div(_,_)). |
| 371 | | worth_it_int_wd(max(_)). |
| 372 | | worth_it_int_wd(min(_)). |
| 373 | | worth_it_int_wd(mod(_,_)). |
| 374 | | worth_it_int_wd(power_of(_,_)). |
| 375 | | worth_it_int_wd(card(_)). % has WD condition !! |
| 376 | | worth_it_int_wd(size(_)). |
| 377 | | |
| 378 | | % other operations that could generate WD-errors |
| 379 | | worth_it_wd(first(_)). |
| 380 | | worth_it_wd(last(_)). |
| 381 | | worth_it_wd(tail(_)). |
| 382 | | worth_it_wd(front(_)). |
| 383 | | worth_it_wd(restrict_front(_,_)). |
| 384 | | worth_it_wd(restrict_tail(_,_)). |
| 385 | | worth_it_wd(rel_iterate(_,_)). %% could be expensive |
| 386 | | worth_it_wd(general_intersection(_)). |
| 387 | | worth_it_wd(general_concat(_)). |
| 388 | | |
| 389 | | % to do: check other operators that could be not well-defined ! |
| 390 | | |
| 391 | | worth_it_int(unary_minus(_)). |
| 392 | | worth_it_int(add(_,_)). |
| 393 | | worth_it_int(minus(_,_)). |
| 394 | | worth_it_int(multiplication(_,_)). |
| 395 | | worth_it_int(max_int). |
| 396 | | worth_it_int(min_int). |
| 397 | | |
| 398 | | %worth_it_set(empty_set). % treated below |
| 399 | | %worth_it_set(empty_sequence). % treated below |
| 400 | | %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))) |
| 401 | | %% ?? need to be more careful here; can be expensive --> need to keep track which parts need definitely to be evaluated |
| 402 | | worth_it_set(integer_set(_)). % will be converted into value(global_set(_)) |
| 403 | ? | worth_it_set(comprehension_set(A,B)) :- b_ast_cleanup:is_integer_set(comprehension_set(A,B),_). |
| 404 | | worth_it_set(interval(_,_)). |
| 405 | | worth_it_set(reflexive_closure(A)) :- \+ symbolic_value(A). |
| 406 | | worth_it_set(reverse(_)). % function inverse |
| 407 | | worth_it_set(domain(_)). worth_it_set(range(_)). |
| 408 | | worth_it_set(union(_,_)). worth_it_set(intersection(_,_)). worth_it_set(set_subtraction(_,_)). |
| 409 | | worth_it_set(image(_,B)) :- \+ symbolic_value(B). |
| 410 | | worth_it_set(composition(_,_)). |
| 411 | | worth_it_set(domain_restriction(_,_)). worth_it_set(domain_subtraction(_,_)). |
| 412 | | worth_it_set(range_restriction(_,_)). worth_it_set(range_subtraction(_,_)). |
| 413 | | worth_it_set(direct_product(A,B)) :- \+ symbolic_value(A), \+ symbolic_value(B). |
| 414 | | worth_it_set(parallel_product(A,B)) :- \+ symbolic_value(A), \+ symbolic_value(B). |
| 415 | | worth_it_set(iteration(_,_)). |
| 416 | | worth_it_set(set_extension([H|_])) :- \+ symbolic_value(H). % otherwise we may get an enumeration warning |
| 417 | | worth_it_set(sequence_extension([H|_])) :- \+ symbolic_value(H). % ditto, TODO: check tail unless expensive |
| 418 | | worth_it_set(rev(_)). % reverse of sequence |
| 419 | | worth_it_set(concat(_,_)). |
| 420 | | worth_it_set(seq(_)). % will be kept symbolic anyway |
| 421 | | worth_it_set(seq1(_)). % will be kept symbolic anyway; relevant for test 1731 |
| 422 | | % f=%x.(x:iseq(struct(a:seq1(NATURAL),b:BOOL))|x) & f([rec(a:[222],b:TRUE)])=[rec(a:[222],b:xx)] & xx=TRUE |
| 423 | | % however: value can be put into a set-extension! |
| 424 | | worth_it_set(iseq(_)). % will be kept symbolic anyway |
| 425 | | worth_it_set(iseq1(_)). % will be kept symbolic anyway |
| 426 | | worth_it_set(perm(_)). % will be kept symbolic anyway |
| 427 | | worth_it_set(pow_subset(_)). % will be kept symbolic anyway |
| 428 | | worth_it_set(pow1_subset(_)). % will be kept symbolic anyway |
| 429 | | worth_it_set(fin_subset(_)). % will be kept symbolic anyway |
| 430 | | worth_it_set(fin1_subset(_)). % will be kept symbolic anyway |
| 431 | | worth_it_set(general_union(X)) :- \+ symbolic_value(X). % otherwise we can get enumeration warnings |
| 432 | | worth_it_set(identity(_)). |
| 433 | | worth_it_set(first_of_pair(_)). % can also produce set |
| 434 | | worth_it_set(second_of_pair(_)). % can also produce set |
| 435 | | worth_it_set(cartesian_product(_,_)). % will usually be kept symbolic |
| 436 | | worth_it_set(string_set). % ensure we have values inside compiled closures, e.g., for custom_explicit_set card computations |
| 437 | | worth_it_set(bool_set). |
| 438 | | |
| 439 | | symbolic_value(b(value(Val),_,_)) :- nonvar(Val), symbolic_val_aux(Val). |
| 440 | | symbolic_val_aux(closure(P,T,B)) :- \+ is_fixed_interval(P,T,B,_,_). |
| 441 | | symbolic_val_aux(global_set(_)). |
| 442 | | |
| 443 | | :- use_module(external_functions,[not_declarative/1,external_fun_has_wd_condition/1, |
| 444 | | expects_unevaluated_args/1]). |
| 445 | | worth_it_other(boolean_true). |
| 446 | | worth_it_other(boolean_false). |
| 447 | | worth_it_other(string(_)). |
| 448 | | worth_it_other(first_of_pair(_)). |
| 449 | | worth_it_other(second_of_pair(_)). |
| 450 | | worth_it_other(couple(_,_)). |
| 451 | | worth_it_other(record_field(_,_)). |
| 452 | | worth_it_other(external_function_call(FunName,_)) :- |
| 453 | | \+ not_declarative(FunName), |
| 454 | | \+ external_fun_has_wd_condition(FunName). %print(compile(FunName)),nl. |
| 455 | | % CHOOSE for finite_non_empty_set ? |
| 456 | | worth_it_other(rec(_)). |
| 457 | | worth_it_other(struct(_)). |
| 458 | | %worth_it_other(value(_)). % does not have to be evaluted; already a value |
| 459 | | |
| 460 | | /* |
| 461 | | % To do: distinguish which parts definitely need to be evaluated |
| 462 | | %dont_eval_subexpressions(member). % special membership code can be used |
| 463 | | %dont_eval_subexpressions(not_member). % special membership code can be used |
| 464 | | dont_eval_subexpressions(disjunct(_,_)). % it may not be necessary to eval RHS |
| 465 | | dont_eval_subexpressions(implication(_,_)). % it may not be necessary to eval RHS |
| 466 | | */ |
| 467 | | |
| 468 | | :- use_module(bsyntaxtree, [get_negated_operator_expr/2]). |
| 469 | | :- use_module(kernel_objects,[equal_object/3]). |
| 470 | | :- use_module(kernel_mappings,[binary_boolean_operator/3]). |
| 471 | | :- use_module(kernel_tools,[filter_cannot_match/4, get_template_for_filter_cannot_match/2]). |
| 472 | | b_compile2(Exp,_Parameters,_LS,_S,NExpr,_Eval,FullyKnown,WF) :- var(Exp), !, |
| 473 | | add_internal_error_wf(b_compiler,'Variable Expression: ',Exp,unknown,WF), |
| 474 | | NExpr=Exp, FullyKnown=false. |
| 475 | | b_compile2(truth,_,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !, NExpr=truth, FullyKnown=false. % predicates never fully known |
| 476 | | b_compile2(falsity,_,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !, NExpr=falsity, FullyKnown=false. % predicates never fully known |
| 477 | | b_compile2(empty_set,_,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !, NExpr=value([]), FullyKnown=true. |
| 478 | | b_compile2(empty_sequence,_,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !, NExpr=value([]), FullyKnown=true. |
| 479 | | b_compile2(boolean_false,_,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !, NExpr=value(pred_false), FullyKnown=true. |
| 480 | | b_compile2(boolean_true,_,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !, NExpr=value(pred_true), FullyKnown=true. |
| 481 | | b_compile2(value(Val),_Parameters,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !, |
| 482 | | NExpr=value(Val), |
| 483 | | (known_value(Val) -> % ground(Val) -> known_value ? |
| 484 | | FullyKnown=true ; FullyKnown=false). |
| 485 | | b_compile2(integer(Val),_Parameters,_LS,_S,NExpr,_Eval,FullyKnown,_WF) :- !, |
| 486 | | NExpr=value(int(Val)), (number(Val) -> FullyKnown=true ; FullyKnown=false). |
| 487 | | b_compile2(lazy_lookup_pred(Id),Parameters,LS,S,NExpr,_Eval,FullyKnown,WF) :- !, |
| 488 | | ( ord_member(Id,Parameters) -> %print(lazy_lookup_pred_id_as_parameter(Id,Parameters)),nl, |
| 489 | | NExpr = lazy_lookup_pred(Id), FullyKnown=false |
| 490 | | ; compute_lazy_lookup(Id,lazy_lookup_pred(Id),LS,S,NExpr,FullyKnown,WF) |
| 491 | | ). |
| 492 | | b_compile2(lazy_lookup_expr(Id),Parameters,LS,S,NExpr,_Eval,FullyKnown,WF) :- !, |
| 493 | | ( ord_member(Id,Parameters) -> %print(lazy_lookup_expr_id_as_parameter(Id,Parameters)),nl, |
| 494 | | NExpr = lazy_lookup_expr(Id), FullyKnown=false |
| 495 | | ; compute_lazy_lookup(Id,lazy_lookup_expr(Id),LS,S,NExpr,FullyKnown,WF) |
| 496 | | ). |
| 497 | | |
| 498 | | % treat a few common cases, more efficiently than syntaxtransformation |
| 499 | | b_compile2(equal(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 500 | | FullyKnown=false, % predicates never evaluated in b_compile1 |
| 501 | ? | b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnownA,WF), |
| 502 | ? | b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnownB,WF), |
| 503 | | ( FullyKnownA=true, FullyKnownB=true, |
| 504 | | NExprA = b(value(VA),_,_), NExprB = b(value(VB),_,_) |
| 505 | | -> (equal_object(VA,VB,b_compile2_1) -> NExpr = truth ; NExpr = falsity) |
| 506 | | ; generate_equality(NExprA,NExprB,NExpr) |
| 507 | | ). |
| 508 | | b_compile2(not_equal(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 509 | | FullyKnown=false, % predicates never evaluated in b_compile1 |
| 510 | | b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnownA,WF), |
| 511 | ? | b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnownB,WF), |
| 512 | | ( FullyKnownA=true, FullyKnownB=true, |
| 513 | | NExprA = b(value(VA),_,_), NExprB = b(value(VB),_,_) |
| 514 | | -> %print(computing_neq(VA,VB)),nl, |
| 515 | | (kernel_objects:equal_object(VA,VB,b_compile2_2) -> NExpr = falsity ; NExpr = truth) |
| 516 | | %, print(result(NExpr)),nl |
| 517 | | ; NExpr = not_equal(NExprA,NExprB) |
| 518 | | ). |
| 519 | | b_compile2(member(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 520 | | FullyKnown=false, % predicates never evaluated in b_compile1 |
| 521 | ? | b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnownB,WF), |
| 522 | | (NExprB = b(value(X),BT,BI) |
| 523 | | -> (X==[], always_well_defined(A) -> NExpr = falsity |
| 524 | ? | ; b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnownA,WF), |
| 525 | | % check if we can decide membership (e.g., 1:{1}) |
| 526 | ? | (quick_test_membership1(NExprA,X,PRes) |
| 527 | | -> convert_pred_res(PRes,NExpr) |
| 528 | | % TO DO: maybe optimize x: {y|P(y)} --> P(x) ; by commenting in code below |
| 529 | | % However, ensure test 273 succeeds and closure equality correctly detected (e.g., for BV16 = {bt|bt : BIT_VECTOR & bv_size(bt) = 16}) |
| 530 | | % ; (get_texpr_id(NExprA,IDA), |
| 531 | | % get_comprehension_set(NExprB,IDB,Pred), get_texpr_info(NExprB,Info), |
| 532 | | % print(rename(IDB,IDA,Info)),nl, |
| 533 | | % bsyntaxtree:rename_bt(Pred,[rename(IDB,IDA)],PredA)) -> get_texpr_expr(PredA,NExpr) |
| 534 | | ; custom_explicit_sets:singleton_set(X,El) % replace x:{El} -> x=El |
| 535 | | -> get_texpr_type(NExprA,TA), |
| 536 | | generate_equality_with_value(NExprA,FullyKnownA,El,FullyKnownB,TA,NExpr) |
| 537 | | ; get_template_for_filter_cannot_match(NExprA,VA) |
| 538 | | -> filter_cannot_match(X,VA,NewX,Filtered), |
| 539 | | % (Filtered=false -> true ; print(filtered(NewX,VA,X)),nl), |
| 540 | | (Filtered=false -> NExpr = member(NExprA,NExprB) |
| 541 | | ; (NewX==[], always_well_defined(A)) -> NExpr = falsity |
| 542 | | ; custom_explicit_sets:singleton_set(NewX,El) |
| 543 | | -> get_texpr_type(NExprA,TA), |
| 544 | | %nl,print(create_equal(NExprA,FullyKnownA,El,FullyKnownB,NExprB)),nl,nl, |
| 545 | | generate_equality_with_value(NExprA,FullyKnownA,El,FullyKnownB,TA,NExpr) |
| 546 | | ; NExpr = member(NExprA, b(value(NewX),BT,BI)) |
| 547 | | ) |
| 548 | | % end fo filtering |
| 549 | | ; NExpr = member(NExprA,NExprB) |
| 550 | | ) |
| 551 | | % , print('compile: '),print(NExpr),nl |
| 552 | | ) |
| 553 | | ; NExpr = member(NExprA,NExprB), |
| 554 | ? | b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF) |
| 555 | | ). |
| 556 | | % TO DO: also optimize things like: (ev1 |-> 0) |-> eg : #221:{((1|->0)|->3),((2|->0)|->0),...,((233|->0)|->218),((234|->0)|->228)} |
| 557 | | |
| 558 | | b_compile2(not_member(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 559 | | FullyKnown=false, % predicates never evaluated in b_compile1 |
| 560 | | b_compile1(B,Parameters,LS,S,NExprB,Eval,_,WF), |
| 561 | | (NExprB = b(value(X),_,_) |
| 562 | | -> (X==[], always_well_defined(A) -> NExpr = truth |
| 563 | | ; b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF), |
| 564 | | (quick_test_membership1(NExprA,X,PRes) |
| 565 | | -> convert_neg_pred_res(PRes,NExpr) |
| 566 | | ; NExpr = not_member(NExprA,NExprB)) |
| 567 | | ) |
| 568 | | ; NExpr = not_member(NExprA,NExprB), |
| 569 | | b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF) |
| 570 | | ). |
| 571 | | b_compile2(function(Fun,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 572 | | (is_lazy_extension_function_for_fun_app(Fun) |
| 573 | | -> Eval1=false % extension function applications treated lazily |
| 574 | | % TO DO: first evaluate B, if known then only evaluate relevant part of extension function |
| 575 | | ; Eval1=Eval), |
| 576 | | b_compile1(Fun,Parameters,LS,S,NExprA,Eval1,FullyKnown1,WF), |
| 577 | | combine_fully_known(FullyKnown1,FullyKnown2,FullyKnown12), |
| 578 | | b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnown2,WF), |
| 579 | | %tools_printing:print_term_summary(compiled_function(FullyKnown1,FullyKnown2,NExprA,NExprB)),nl, |
| 580 | | (FullyKnown2=true, |
| 581 | | (NExprA=b(value(_),_,_) -> true % no WD issue can be removed by apply, value already computed |
| 582 | | ; preferences:preference(find_abort_values,false) % in a sequence extension we could remove non-WD elements |
| 583 | | ), |
| 584 | | % check if we have enough information to apply a partially specified function as a list |
| 585 | | % 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 ! |
| 586 | ? | can_apply_partially_specified_function(NExprA,NExprB,ResultExpr,WF) |
| 587 | | -> NExpr = ResultExpr, |
| 588 | | (FullyKnown12=true -> FullyKnown=true |
| 589 | | ; ResultExpr=value(ResultValue),known_value(ResultValue) -> FullyKnown=true |
| 590 | | ; FullyKnown = false) |
| 591 | | ; %tools_printing:print_term_summary(cannot_apply_function(FullyKnown2,NExprA,NExprB)),nl, |
| 592 | | %translate:print_bexpr(NExprA),nl, translate:print_bexpr(NExprB),nl, |
| 593 | | NExpr = function(NExprA,NExprB), FullyKnown = FullyKnown12). |
| 594 | | |
| 595 | | b_compile2(conjunct(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 596 | | FullyKnown=false, % predicates never automatically evaluated in b_compile1 |
| 597 | ? | b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF), |
| 598 | | (is_falsity(NExprA) -> NExpr = falsity |
| 599 | | ; |
| 600 | | % TO DO: propagate static information from A to B, e.g. if A :: x=10 -> add x=10 to LS/Parameters |
| 601 | | % also: try and detect unsatisfiable predicates beforehand |
| 602 | ? | b_compile1(B,Parameters,LS,S,NExprB,Eval,_,WF), |
| 603 | | (is_falsity(NExprB) -> NExpr = falsity |
| 604 | | ; is_truth(NExprB) -> get_texpr_expr(NExprA,NExpr) |
| 605 | | ; is_truth(NExprA) -> get_texpr_expr(NExprB,NExpr) |
| 606 | | ; NExpr = conjunct(NExprA,NExprB)) |
| 607 | | ). |
| 608 | | b_compile2(disjunct(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 609 | | FullyKnown=false, % predicates never automatically evaluated in b_compile1 |
| 610 | ? | b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF), |
| 611 | | (is_truth(NExprA) -> NExpr = truth |
| 612 | ? | ; 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 |
| 613 | | (is_truth(NExprB) -> NExpr = truth |
| 614 | | ; is_falsity(NExprA) -> get_texpr_expr(NExprB,NExpr) |
| 615 | | ; is_falsity(NExprB) -> get_texpr_expr(NExprA,NExpr) |
| 616 | | ; NExpr = disjunct(NExprA,NExprB)) |
| 617 | | ). |
| 618 | | b_compile2(implication(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 619 | | FullyKnown=false, % predicates never automatically evaluated in b_compile1 |
| 620 | | b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF), |
| 621 | | (is_falsity(NExprA) -> NExpr = truth |
| 622 | | ; is_truth(NExprA) -> b_compile1(B,Parameters,LS,S,NExprB,Eval,_,WF), get_texpr_expr(NExprB,NExpr) |
| 623 | | ; NExpr = implication(NExprA,NExprB), |
| 624 | | b_compile1(B,Parameters,LS,S,NExprB,false,_,WF) % B does not have to be executed in a successful branch: set Eval to false to avoid computing expensive expressions which may not be needed |
| 625 | | % TO DO: add preference to force pre-computation everywhere and pass Eval instead of false to b_compile1; ditto for disjunction |
| 626 | | ). |
| 627 | | b_compile2(negation(A),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 628 | | FullyKnown=false, % predicates never automatically evaluated in b_compile1 |
| 629 | ? | b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF), |
| 630 | | ( get_negated_operator_expr(NExprA,NegatedA) -> NExpr = NegatedA |
| 631 | | ; NExpr = negation(NExprA) |
| 632 | | ). |
| 633 | | b_compile2(if_then_else(A,B,C),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 634 | | b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF), |
| 635 | ? | (is_falsity(NExprA) -> b_compile1(C,Parameters,LS,S,NExprC,Eval,FullyKnown,WF), get_texpr_expr(NExprC,NExpr) |
| 636 | ? | ; is_truth(NExprA) -> b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnown,WF), get_texpr_expr(NExprB,NExpr) |
| 637 | | ; NExpr = if_then_else(NExprA,NExprB,NExprC), FullyKnown=false, |
| 638 | | b_compile1(B,Parameters,LS,S,NExprB,false,_,WF), % set Eval to false as we do not know if B will be needed |
| 639 | | b_compile1(C,Parameters,LS,S,NExprC,false,_,WF) % ditto for C |
| 640 | | ). |
| 641 | | /* b_compile2(comprehension_set(CParas,Body),Parameters,LS,S,NExpr,_Eval,FullyKnown,WF) :- |
| 642 | | sort(Parameters,SParas), |
| 643 | | b_ast_cleanup:not_occurs_in_predicate(SParas,Body), %can only be applied if Body does not reference Parameters |
| 644 | | !, |
| 645 | | b_generate_inner_closure_if_necessary(Parameters,CParas,Body,LS,S,Result), % will itself call b_compile |
| 646 | | NExpr = value(Result), |
| 647 | | (ground(Result) -> FullyKnown=true ; FullyKnown=false). */ |
| 648 | | b_compile2(forall(ForallPara,A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 649 | | FullyKnown=false, % predicates never automatically evaluated in b_compile1 |
| 650 | | get_texpr_ids(ForallPara,AtomicIds), |
| 651 | | add_parameters(Parameters,AtomicIds,NParameters), |
| 652 | | b_compile1(A,NParameters,LS,S,NA,Eval,_FullyKnownA,WF), |
| 653 | | (is_falsity(NA) -> NExpr = truth |
| 654 | | ; b_compile1(B,NParameters,LS,S,NB,Eval,_FullyKnownB,WF), |
| 655 | | (is_truth(NB) -> NExpr = truth |
| 656 | | ; NExpr = forall(ForallPara,NA,NB) |
| 657 | | % TO DO ??: if we have an equality -> replace Body by value and remove quantifier |
| 658 | | %,print('COMPIlED: '),translate:print_bexpr(b(NExpr,pred,[])),nl |
| 659 | | ) |
| 660 | | ). |
| 661 | | % some special cases to avoid calling syntaxtransformation |
| 662 | | b_compile2(record_field(A,FieldName),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 663 | | b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnownA,WF), |
| 664 | | % First: we can try compute even if value not fully known !, we just need record field list |
| 665 | | (get_record_field(NExprA,FieldName,NExpr,FullyKnown) -> true |
| 666 | | ; NExpr = record_field(NExprA,FieldName), FullyKnown=FullyKnownA). |
| 667 | | b_compile2(couple(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 668 | | %NExpr = couple(NExprA,NExprB), |
| 669 | | b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnown1,WF), |
| 670 | | combine_fully_known(FullyKnown1,FullyKnown2,FullyKnown), |
| 671 | ? | b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnown2,WF), |
| 672 | | (FullyKnown \== true, % evaluation will already combine the result |
| 673 | | NExprA=b(value(VA),_,_),NExprB=b(value(VB),_,_) |
| 674 | | -> NExpr = value((VA,VB)) |
| 675 | | ; NExpr = couple(NExprA,NExprB)). |
| 676 | | b_compile2(image(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 677 | ? | b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnown1,WF), |
| 678 | | combine_fully_known(FullyKnown1,FullyKnown2,FullyKnown), |
| 679 | | b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnown2,WF), |
| 680 | | (FullyKnown \= true, NExprA=b(value(VA),BT,BI), |
| 681 | | NExprB=b(value(VB),_,_), nonvar(VB), |
| 682 | | custom_explicit_sets:singleton_set(VB,VBX) |
| 683 | | -> filter_cannot_match(VA,(VBX,_),NewVA,_Filtered), %nl,print(filtered_image(VBX,VA,NewVA)),nl, |
| 684 | | NExpr = image(b(value(NewVA),BT,BI),NExprB) |
| 685 | | % TO DO: add case where VB==[] or VA==[] are the empty set |
| 686 | | ; NExpr = image(NExprA,NExprB) |
| 687 | | ). %, print('compile image: '),translate:print_bexpr(NExpr),nl. |
| 688 | | % TO DO: do something like can_apply_partially_specified_function; or filter_can_match |
| 689 | | b_compile2(composition(A,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 690 | | b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnown1,WF), |
| 691 | | combine_fully_known(FullyKnown1,FullyKnown2,FullyKnown), |
| 692 | | NExpr = composition(NExprA,NExprB), |
| 693 | | b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnown2,WF), |
| 694 | | (FullyKnown=false, Eval=eval, performance_monitoring_on, |
| 695 | | ( FullyKnown1=true, NExprB=b(value(_),_,Info), large_known_value(NExprA,2) |
| 696 | | -> true %translate:nested_print_bexpr(NExprB),nl |
| 697 | | ; FullyKnown2=true, NExprA=b(value(_),_,Info), large_known_value(NExprB,2) |
| 698 | | -> true %translate:nested_print_bexpr(NExprA),nl |
| 699 | | ) |
| 700 | | -> perfmessage(b_compiler,'Cannot compile relational composition (try lift it out of quantification)',Info) |
| 701 | | ; true). |
| 702 | | b_compile2(assertion_expression(A,Msg,B),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 703 | | b_compile1(A,Parameters,LS,S,NExprA,Eval,_,WF), |
| 704 | | (is_truth(NExprA) -> % the ASSERT EXPR is redundant |
| 705 | | %print(removed_assert),nl, translate:print_bexpr(B),nl, |
| 706 | | b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnown,WF), |
| 707 | | get_texpr_expr(NExprB,NExpr) |
| 708 | | ; b_compile1(B,Parameters,LS,S,NExprB,Eval,_,WF), |
| 709 | | FullyKnown=false, % we cannot get rid of WD condition |
| 710 | | NExpr = assertion_expression(NExprA,Msg,NExprB) |
| 711 | | ). |
| 712 | | b_compile2(domain(A),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 713 | | b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnown1,WF), |
| 714 | | (FullyKnown1=false,get_texpr_expr(NExprA,NA),evaluate_domain(NA,Domain) % try and compute domain even if not fully known |
| 715 | | -> FullyKnown = true, NExpr = value(Domain) |
| 716 | | ; FullyKnown = FullyKnown1, NExpr = domain(NExprA)). |
| 717 | | b_compile2(range(A),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 718 | | b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnown1,WF), |
| 719 | | (FullyKnown1=false,evaluate_range(NExprA,Range) % try and compute range even if not fully known |
| 720 | | -> FullyKnown = true, NExpr = value(Range) |
| 721 | | ; FullyKnown = FullyKnown1, NExpr = range(NExprA)). |
| 722 | | b_compile2(assign(LHS_List,RHS_List),Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- !, |
| 723 | | NExpr = assign(New_LHS_List,NewRHS_List), FullyKnown = false, |
| 724 | | maplist(b_compile_lhs(Parameters,LS,S,Eval,WF),LHS_List,New_LHS_List), |
| 725 | ? | b_compile_l(RHS_List,Parameters,LS,S,NewRHS_List,Eval,_FullyKnown2,WF). |
| 726 | | b_compile2(assign_single_id(ID,B),Parameters,LS,S,assign_single_id(ID,NExprB),Eval,FullyKnown,WF) :- !, |
| 727 | | FullyKnown = false, |
| 728 | | b_compile1(B,Parameters,LS,S,NExprB,Eval,_,WF). |
| 729 | | b_compile2(operation_call(Operation,OpCallResults,OpCallParas),Parameters,LS,S,InlinedOpCall,Eval,FullyKnown,WF) :- |
| 730 | | % TO DO: evaluate if we should also use the let_expression_global approach used for operation_call_in_expr |
| 731 | | !, |
| 732 | | def_get_texpr_id(Operation,op(OperationName)), |
| 733 | | FullyKnown = false, |
| 734 | | b_compile_l(OpCallParas,Parameters,LS,S,OpCallParaValues,Eval,_,WF), |
| 735 | | TopLevel=false, |
| 736 | | b_get_machine_operation_for_animation(OperationName,OpResults,OpFormalParameters,Body,_OType,TopLevel), |
| 737 | ? | bsyntaxtree:replace_ids_by_exprs(Body,OpResults,OpCallResults,Body2), |
| 738 | | get_texpr_ids(OpFormalParameters,OpIds), |
| 739 | | add_parameters(Parameters,OpIds,InnerParas), |
| 740 | ? | b_compile1(Body2,InnerParas,[],S,NBody,Eval,FullyKnown,WF), % do not pass local state: this may override constants,... from the called machine |
| 741 | | % Note: global state S should be valid for all machines in currently loaded specification |
| 742 | | get_texpr_ids(OpCallResults,OpRIds), |
| 743 | | add_parameters(Parameters,OpRIds,LocalKnownParas), |
| 744 | | simplify_assignment(OpFormalParameters,OpCallParaValues,LHSFormalParas,RHSCallVals), %% |
| 745 | | split_formal_parameters(LHSFormalParas,RHSCallVals,LocalKnownParas, |
| 746 | | FreshOpParas,FreshCallVals, |
| 747 | | ClashOpParas, ClashCallVals), % only set up VAR for fresh Paras |
| 748 | | % print(split(LHSFormalParas,LocalKnownParas,fresh(FreshOpParas),clash(ClashOpParas))),nl, |
| 749 | | (FreshOpParas=[] -> get_texpr_expr(NBody,Let1) |
| 750 | | ; create_equality_for_let(FreshOpParas,FreshCallVals,Equality1), |
| 751 | | Let1 = let(FreshOpParas,Equality1,NBody)), |
| 752 | | (ClashOpParas = [] |
| 753 | | -> InlinedOpCall = Let1 |
| 754 | | ; %nl,print(clash(ClashOpParas)),nl, |
| 755 | | maplist(create_fresh_id,ClashOpParas,FreshCopy), |
| 756 | | create_equality_for_let(ClashOpParas,FreshCopy,Equality2), % copy Values from Fresh Ids |
| 757 | | create_equality_for_let(FreshCopy,ClashCallVals,Equality3), % assign Parameter Vals to Fresh Ids |
| 758 | | get_texpr_pos(Body,BodyPos), BodyPosInfo = [nodeid(BodyPos)], |
| 759 | | Let2 = let(ClashOpParas,Equality2,b(Let1,subst,[BodyPosInfo])), |
| 760 | | InlinedOpCall = let(FreshCopy,Equality3,b(Let2,subst,[BodyPosInfo])) |
| 761 | | ). |
| 762 | | %, print('Compiled operation call: '), translate:print_subst(b(InlinedOpCall,subst,BodyPosInfo)),nl,nl. |
| 763 | | % Maybe this version is faster when no OpCallResults: |
| 764 | | %b_compile2(operation_call(Operation,OpCallResults,OpCallParas),Parameters,LS,S,InlinedOpCall,Eval,FullyKnown,WF) :- |
| 765 | | % OpCallResults=[], |
| 766 | | % !, |
| 767 | | % def_get_texpr_id(Operation,op(OperationName)), |
| 768 | | % FullyKnown = false, |
| 769 | | %% b_compile_l(Results,Parameters,LS,S,NResults,Eval,_,WF), |
| 770 | | % b_compile_l(OpCallParas,Parameters,LS,S,OpCallParaValues,Eval,_,WF), |
| 771 | | % TopLevel=false, |
| 772 | | % b_get_machine_operation_for_animation(OperationName,OpResults,OpParameters,Body,_OType,TopLevel), |
| 773 | | % % Note: input parameters cannot be assigned to: so replace ids is ok |
| 774 | | % % However, we cannot replace output parameters: these can be assigned to and we can have aliasing |
| 775 | | % % Note: no aliasing is allowed in OpCallResults (cf Atelier-B handbook x,x <-- op not allowed) |
| 776 | | % bsyntaxtree:replace_ids_by_exprs(Body,OpParameters,OpCallParaValues,Body2), |
| 777 | | % get_texpr_ids(OpResults,OpIds), |
| 778 | | % append(OpIds,Parameters,InnerParas), |
| 779 | | % b_compile1(Body2,InnerParas,LS,S,NBody,Eval,FullyKnown,WF), |
| 780 | | % FinalBody = NBody. |
| 781 | | b_compile2(Expr,Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- |
| 782 | | functor(Expr,BOP,2), |
| 783 | | binary_boolean_operator(BOP,_,_),!, % from kernel_mappings, slightly more efficient than syntaxtransformation |
| 784 | | arg(1,Expr,A), |
| 785 | | FullyKnown=false, % predicates never evaluated in b_compile1 |
| 786 | | b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnownA,WF), |
| 787 | | arg(2,Expr,B), |
| 788 | ? | b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnownB,WF), |
| 789 | ? | (eval_binary_bool(FullyKnownA,NExprA,FullyKnownB,NExprB,BOP,Result) |
| 790 | | -> NExpr = Result |
| 791 | | ; functor(NExpr,BOP,2), arg(1,NExpr,NExprA), arg(2,NExpr,NExprB) |
| 792 | | ). |
| 793 | | b_compile2(external_function_call(ExtFun,Args),_Parameters,LS,_S,NExpr,_Eval,FullyKnown,_WF) :- |
| 794 | | expects_unevaluated_args(ExtFun), |
| 795 | | memberchk(bind('$optimize_do_not_force_lazy_lookups',_),LS), % this is an optimize call |
| 796 | | !, |
| 797 | | debug_format(9,'Not compiling external function call to ~w~n',[ExtFun]), |
| 798 | | NExpr=external_function_call(ExtFun,Args), |
| 799 | | FullyKnown=false. |
| 800 | | b_compile2(Expr,Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- |
| 801 | | functor(Expr,BOP,2), |
| 802 | | kernel_mappings:binary_function(BOP,_,_),!, % slightly more efficient than syntaxtransformation |
| 803 | | arg(1,Expr,A), |
| 804 | ? | b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnownA,WF), |
| 805 | | combine_fully_known(FullyKnownA,FullyKnownB,FullyKnown), |
| 806 | | arg(2,Expr,B), |
| 807 | ? | b_compile1(B,Parameters,LS,S,NExprB,Eval,FullyKnownB,WF), |
| 808 | | functor(NExpr,BOP,2), arg(1,NExpr,NExprA), arg(2,NExpr,NExprB). |
| 809 | | b_compile2(Expr,Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- |
| 810 | | functor(Expr,UOP,1), |
| 811 | | kernel_mappings:unary_function(UOP,_,_),!, % slightly more efficient than syntaxtransformation |
| 812 | | arg(1,Expr,A), |
| 813 | ? | b_compile1(A,Parameters,LS,S,NExprA,Eval,FullyKnown,WF), |
| 814 | | functor(NExpr,UOP,1), arg(1,NExpr,NExprA). |
| 815 | | b_compile2(Expr,Parameters,LS,S,NExpr,Eval,FullyKnown,WF) :- % GENERAL CASE |
| 816 | | %hit_profiler:add_profile_hit(Expr), |
| 817 | ? | syntaxtransformation(Expr,Subs,Names,NSubs,NExpr), |
| 818 | | get_texpr_ids(Names,Ids), |
| 819 | | add_parameters(Parameters,Ids,NParameters), |
| 820 | ? | b_compile_l(Subs,NParameters,LS,S,NSubs,Eval,FullyKnown,WF). |
| 821 | | |
| 822 | | b_compile_l([],_,_,_,[],_Eval,true,_WF). |
| 823 | | b_compile_l([Expr|ExprRest],P,LS,S,[NExpr|NExprRest],Eval,FullyKnown,WF) :- |
| 824 | ? | b_compile1(Expr,P,LS,S,NExpr,Eval,FullyKnown1,WF), |
| 825 | | combine_fully_known(FullyKnown1,FullyKnown2,FullyKnown), |
| 826 | ? | b_compile_l(ExprRest,P,LS,S,NExprRest,Eval,FullyKnown2,WF). |
| 827 | | |
| 828 | | % detecth when a parameter clashes with existing known ids |
| 829 | ? | id_clash(LocalKnownParas,TID) :- def_get_texpr_id(TID,ID), member(ID,LocalKnownParas). |
| 830 | | |
| 831 | | /* comment in if we want to compile inner comprehension sets: |
| 832 | | :- use_module(bsyntaxtree,[split_names_and_types/3]). |
| 833 | | :- use_module(closures,[construct_closure_if_necessary/4]). |
| 834 | | b_generate_inner_closure_if_necessary(OuterParameters,ClosureParas,Condition,LocalState,State,Result) :- |
| 835 | | split_names_and_types(ClosureParas,Names,Types), |
| 836 | | add_parameters(OuterParameters,Names,FullNames), |
| 837 | | b_compile(Condition,FullNames,LocalState,State,ClosurePred), |
| 838 | | print('INNER COMPILE: '), translate:print_bexpr(ClosurePred),nl, |
| 839 | | construct_closure_if_necessary(Names,Types,ClosurePred,Result). |
| 840 | | */ |
| 841 | | |
| 842 | | |
| 843 | | % the LHS contains l-values which should not be looked up in the environment |
| 844 | | % however, we need to deal with things like f(i) := RHS and compile i |
| 845 | | b_compile_lhs(Parameters,LS,S,Eval,WF,TExpr,NewTExpr) :- |
| 846 | | TExpr = b(Expr,Type,Info), NewTExpr = b(NewExpr,Type,Info), |
| 847 | | b_compile_lhs_aux(Expr,Parameters,LS,S,NewExpr,Eval,WF). |
| 848 | | |
| 849 | | b_compile_lhs_aux(function(A,B),Parameters,LS,S,function(NewA,NewB),Eval,WF) :- !, |
| 850 | | b_compile_lhs(Parameters,LS,S,Eval,WF,A,NewA), % we can have nexted function calls f(e)(g) := |
| 851 | | b_compile1(B,Parameters,LS,S,NewB,Eval,_,WF). |
| 852 | | b_compile_lhs_aux(E,_,_,_,E,_,_WF). % other LHS should be identifier -> just copy |
| 853 | | |
| 854 | | get_record_field(b(value(Val),_,_),FieldName,value(Field),FullyKnown) :- !, |
| 855 | | nonvar(Val), Val=rec(Fields), |
| 856 | | safe_get_field(Fields,FieldName,Field), |
| 857 | | known_value(Field,FullyKnown). |
| 858 | | get_record_field(b(function(FUN,ARG),_Type,_Info),FieldName,function(ReducedFUN,ARG),false) :- |
| 859 | | % {1|->rec(a:1,b:2),...}(x)'b --> {1|->2,...}(x) |
| 860 | | %nl,print(get_field(FUN,ARG,FieldName)),nl, |
| 861 | | % TO DO: also allow nested functions calls {1|->rec(a:1,b:2),...}(x)(y)'b or other reduction operators |
| 862 | | get_field_in_range(FUN,FieldName,ReducedFUN). |
| 863 | | safe_get_field(V,FN,_) :- (var(V) ; var(FN)),!,fail. |
| 864 | | safe_get_field([field(N,V)|T],FieldName,Result) :- nonvar(N), |
| 865 | | (N=FieldName -> Result=V ; safe_get_field(T,FieldName,Result)). |
| 866 | | |
| 867 | | :- use_module(probsrc(custom_explicit_sets),[expand_custom_set_to_list/4, convert_to_avl/2]). |
| 868 | | :- use_module(probsrc(avl_tools),[avl_height_less_than/2]). |
| 869 | | get_field_in_range(b(value(OldVal),set(couple(Dom,OldRange)),Info),FieldName, |
| 870 | | b(value(NewVal),set(couple(Dom,NewRange)),Info)) :- |
| 871 | | nonvar(OldVal), OldVal=avl_set(AVL), |
| 872 | | avl_height_less_than(AVL,10), |
| 873 | | OldRange = record(Fields), |
| 874 | ? | member(field(FieldName,NewRange),Fields),!, |
| 875 | | expand_custom_set_to_list(avl_set(AVL),List,_,get_field_in_range), |
| 876 | | maplist(safe_get_range_field(FieldName),List,NewList), |
| 877 | | convert_to_avl(NewList,NewVal). |
| 878 | | |
| 879 | | % compute the field access for the range elements: |
| 880 | | safe_get_range_field(FieldName,(Dom,rec(Fields)),(Dom,Field)) :- safe_get_field(Fields,FieldName,Field). |
| 881 | | |
| 882 | | |
| 883 | | eval_binary_bool(true,b(value(ValA),_,_),true,b(value(ValB),_,_),BOP,Result) :- |
| 884 | | ground(ValA), |
| 885 | | ground(ValB), |
| 886 | ? | eval_binary_aux(BOP,ValA,ValB,Result). |
| 887 | | |
| 888 | | eval_binary_aux(less,int(A),int(B),Result) :- |
| 889 | | (A < B -> Result = truth ; Result = falsity). |
| 890 | | eval_binary_aux(greater,int(A),int(B),Result) :- |
| 891 | | (A > B -> Result = truth ; Result = falsity). |
| 892 | | eval_binary_aux(less_equal,int(A),int(B),Result) :- |
| 893 | | (A =< B -> Result = truth ; Result = falsity). |
| 894 | | eval_binary_aux(greater_equal,int(A),int(B),Result) :- |
| 895 | | (A >= B -> Result = truth ; Result = falsity). |
| 896 | | eval_binary_aux(subset,avl_set(A1),avl_set(A2),Result) :- |
| 897 | | (custom_explicit_sets:check_avl_subset(A1,A2) -> Result = truth ; Result = falsity). |
| 898 | | eval_binary_aux(subset,[],_,Result) :- Result=truth. |
| 899 | | %eval_binary_aux(less_real,real(A),real(B),Result) :- % TO DO |
| 900 | | % (A < B -> Result = truth ; Result = falsity). |
| 901 | | % TO DO: other operators are not_subset, strict_subset, ... intervals for subset,... |
| 902 | | |
| 903 | | |
| 904 | | |
| 905 | | :- use_module(store,[lookup_value_for_existing_id_wf/5]). |
| 906 | | compute_lazy_lookup(Id,Expr,LS,S,NExpr,FullyKnown,WF) :- |
| 907 | | lookup_value_for_existing_id_wf(Id,LS,S,(Evaluated,Value),WF), |
| 908 | | % the lazy expression has already been registered, but maybe not yet evaluated |
| 909 | | !, |
| 910 | | known_value(Value,FullyKnown), % compute if value fully known |
| 911 | | (Evaluated==pred_true -> NExpr = value(Value) |
| 912 | | ; FullyKnown==true -> NExpr = value(Value) |
| 913 | | ; memberchk(bind('$optimize_do_not_force_lazy_lookups',_),LS) |
| 914 | | -> NExpr = Expr % we do not force lookup: there could be WD issues ! |
| 915 | | % TO DO: examine Infos for wd_condition; we could also return NExpr = lazy_value(Id,Evaluated,Value) |
| 916 | | ; if(Evaluated = pred_true, |
| 917 | | % will force evaluation ! Note: this means shared expression inside a compiled expression must be well-defined |
| 918 | | NExpr = value(Value), |
| 919 | | (add_internal_error_wf(b_compiler,'Compilation failed: ', Id, unknown,WF), |
| 920 | | fail)) |
| 921 | | ). |
| 922 | | compute_lazy_lookup(Id,_E,_LS,_S,_LazyValue,_,WF) :- |
| 923 | | add_internal_error_wf(b_compiler,'Compilation failed, illegal lazy_lookup_value: ',Id,unknown,WF), |
| 924 | | fail. |
| 925 | | |
| 926 | | combine_fully_known(true,A,A). |
| 927 | | combine_fully_known(false,_,false). |
| 928 | | |
| 929 | | :- use_module(tools_lists,[length_greater/2]). |
| 930 | | % is an extension function with at least two elements, but not too long |
| 931 | | % (for long set extensions it is much better to compile them to avl once; see private_examples/ClearSy/2019_Sep/rule_dummy) |
| 932 | | % extension functions are treated lazily in b_interpreter for function application under the condition: |
| 933 | | % memberchk(contains_wd_condition,FInfo) ; preferences:preference(use_clpfd_solver,false) ; ground_value(ArgValue) |
| 934 | | is_lazy_extension_function_for_fun_app(b(A,_,FInfo)) :- |
| 935 | | preferences:preference(data_validation_mode,false), |
| 936 | | (memberchk(contains_wd_condition,FInfo) -> Lim=98 ; Lim = 23), |
| 937 | | is_extension_function_aux(A,Lim). |
| 938 | | is_extension_function_aux(set_extension([_A,_|T]),Lim) :- \+ length_greater(T,Lim). |
| 939 | | is_extension_function_aux(sequence_extension([_,_|T]),Lim) :- \+ length_greater(T,Lim). |
| 940 | | |
| 941 | | :- use_module(bsyntaxtree,[is_set_type/2]). |
| 942 | | % check if we can apply an argument to a partially specified function (as a list and now also as AVL) |
| 943 | | %can_apply_partially_specified_function(Fun,X,_,_) :- print(fun(Fun)),nl,print(val(X)),nl,fail. |
| 944 | | can_apply_partially_specified_function(b(Expr,TYPE,_), b(value(X),TA,_),ResultExpr,WF) :- |
| 945 | ? | can_apply_aux(Expr,TYPE,X,TA,ResultExpr,WF). |
| 946 | | |
| 947 | | can_apply_aux(value(VAL),TYPE,X,TA,value(ResultValue),WF) :- |
| 948 | | is_set_type(TYPE,couple(TA,_TB)), |
| 949 | ? | lookup_result(VAL,X,ResultValue,WF). |
| 950 | | can_apply_aux(sequence_extension(List),_,X,integer,ResultExpr,_WF) :- |
| 951 | | % important, e.g., for solving test 1551: {b|[a,b,c](2)=333} =res & a : res & b:res |
| 952 | | nonvar(X), X=int(Index), number(Index), |
| 953 | | % this will prevent computing rest of sequence extension: can hide WD issues ! |
| 954 | | % print(apply_seq_extension(Index,List)),nl, |
| 955 | | nth1(Index,List,b(ResultExpr,_,_)). |
| 956 | | |
| 957 | | :- use_module(kernel_equality,[equality_objects_wf/4, equality_can_be_decided_by_unification/1]). |
| 958 | | %lookup_result(VAR,ArgValue,Result,WF) :- var(VAR),!,kernel_mappings:kernel_call_apply_to(VAR,ArgValue,Result,unknown,unknown,WF). |
| 959 | | % 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 ! |
| 960 | | % the idea was to avoid that we wait on the full function, before compiled closure can be evaluated; test 1552 |
| 961 | | % important for e.g. a = {(1, {([]|->2)} ), (2, const(1, [a(1)]))} |
| 962 | | % 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})} |
| 963 | | % test 1552 is currently skipped |
| 964 | | % 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 |
| 965 | | lookup_result(VAR,_,_,_WF) :- var(VAR),!,fail. |
| 966 | | lookup_result(avl_set(A),X,Result,_WF) :- |
| 967 | ? | (custom_explicit_sets:try_apply_to_avl_set(X,Result,A) |
| 968 | | -> true % precompiled function application |
| 969 | | ; debug_format(19,'Function application in b_compiler for avl_set is not well-defined for: ~w~n',[X]), |
| 970 | | % We could transform the function application into a construct that raises a WD error |
| 971 | | fail). |
| 972 | | lookup_result(closure(_P,_T,_B),_X,_Result,_WF) :- !, |
| 973 | | fail. % TODO: should we replace parameters by values in body? if domain is full type? |
| 974 | | lookup_result(List,X,Result,WF) :- List = [_|_],equality_can_be_decided_by_unification(X),!, |
| 975 | | % this is relevant for long lists, |
| 976 | | % see public_examples/B/ExternalFunctions/Satsolver/QueensBoardVersionTF_Satsolver.mch |
| 977 | | fast_lookup_result(List,X,Result,WF). |
| 978 | | lookup_result(List,X,Result,WF) :- |
| 979 | | regular_lookup_result_in_list(List,X,Result,WF). |
| 980 | | |
| 981 | | regular_lookup_result_in_list([],X,_Result,_WF) :- |
| 982 | | debug_format(19,'Function application in b_compiler for list is not well-defined for: ~w~n',[X]), % ditto |
| 983 | | fail. |
| 984 | | regular_lookup_result_in_list([(HFrom,HTo)|T],X,Result,WF) :- |
| 985 | | equality_objects_wf(HFrom,X,PredRes,WF), |
| 986 | | %kernel_equality:equality_objects1(HFrom,X,PredRes,WF), % this could be called if X is guaranteed nonvar |
| 987 | | nonvar(PredRes), % only proceed if we have enough information to determine the result of the comparison |
| 988 | | (PredRes = pred_true -> Result = HTo % we have found the value; we assume there is no other value later |
| 989 | | % TO DO: if find_abort_values=true: look later in the list if for all other HFrom PredRes=pred_false |
| 990 | | ; regular_lookup_result_in_list(T,X,Result,WF)). |
| 991 | | |
| 992 | | % a faster version which does not use equality_objects_wf |
| 993 | | fast_lookup_result([(HFrom,HTo)|T],X,Result,WF) :- |
| 994 | | equality_can_be_decided_by_unification(HFrom), !, |
| 995 | | (HFrom=X -> Result = HTo |
| 996 | | ; fast_lookup_result(T,X,Result,WF) |
| 997 | | ). |
| 998 | | fast_lookup_result(List,X,Result,WF) :- |
| 999 | | regular_lookup_result_in_list(List,X,Result,WF). |
| 1000 | | |
| 1001 | | |
| 1002 | | % get_comprehension_set(b(SET,_,_),ID,PRED) :- get_comprehension_set_aux(SET,ID,PRED). |
| 1003 | | % get_comprehension_set_aux(comprehension_set([TID],PRED),ID,PRED) :- |
| 1004 | | % get_texpr_id(TID,ID). |
| 1005 | | % get_comprehension_set_aux(value(V),ID,PRED) :- nonvar(V), V = closure([ID],_,PRED). |
| 1006 | | |
| 1007 | | |
| 1008 | | |
| 1009 | | |
| 1010 | | quick_test_membership1(b(value(VA),_,_),VB,Result) :- |
| 1011 | ? | quick_test_membership_aux(VB,VA,Result). |
| 1012 | | quick_test_membership_aux(VAR,_,_) :- var(VAR),!,fail. |
| 1013 | | quick_test_membership_aux([],_,pred_false). |
| 1014 | | quick_test_membership_aux(avl_set(AVL),X,Result) :- |
| 1015 | | 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) |
| 1016 | | quick_test_membership_aux(global_set(GS),X,Result) :- nonvar(X), X=int(IX), nonvar(IX), |
| 1017 | | custom_explicit_sets:membership_global_set(GS,X,R,_WF), |
| 1018 | | nonvar(R), Result=R. |
| 1019 | | quick_test_membership_aux(closure(P,T,B),X,Result) :- nonvar(X), X=int(IX), nonvar(IX), |
| 1020 | | is_fixed_interval(P,T,B,LOW,UP), |
| 1021 | | kernel_equality:in_nat_range_test(X,int(LOW),int(UP),R), |
| 1022 | | nonvar(R), Result=R. |
| 1023 | | quick_test_membership_aux(closure(P,T,B),X,Result) :- X==[], % check {} : POW(_) / FIN(_) and {} : POW1(_) / FIN1(_) |
| 1024 | ? | custom_explicit_sets:is_powerset_closure(closure(P,T,B),Kind,_), |
| 1025 | | (contains_empty_set(Kind) -> Result = pred_true ; Result=pred_false). |
| 1026 | | |
| 1027 | | is_fixed_interval(P,T,B,LOW,UP) :- |
| 1028 | | custom_explicit_sets:is_interval_closure(P,T,B,LOW,UP), integer(LOW),integer(UP). |
| 1029 | | |
| 1030 | | contains_empty_set(pow). |
| 1031 | | contains_empty_set(fin). |
| 1032 | | |
| 1033 | | convert_pred_res(pred_false,falsity). |
| 1034 | | convert_pred_res(pred_true,truth). |
| 1035 | | convert_neg_pred_res(pred_true,falsity). |
| 1036 | | convert_neg_pred_res(pred_false,truth). |
| 1037 | | |
| 1038 | | generate_equality(b(A,_,_),b(B,_,_),Res) :- |
| 1039 | | ( generate_equality_aux(A,B,Res) ; |
| 1040 | | generate_equality_aux(B,A,Res) ), |
| 1041 | | !. |
| 1042 | | generate_equality(A,B,equal(A,B)). |
| 1043 | | |
| 1044 | | generate_equality_aux(convert_bool(AA),value(PT),Res) :- |
| 1045 | | PT==pred_true, |
| 1046 | | get_texpr_expr(AA,TA), |
| 1047 | | !, |
| 1048 | | Res = TA. |
| 1049 | | generate_equality_aux(convert_bool(AA),value(PF),Res) :- |
| 1050 | | PF==pred_false,!, |
| 1051 | | Res = negation(AA). |
| 1052 | | |
| 1053 | | % generate an equal(_,_) node where the second one is a Value |
| 1054 | | generate_equality_with_value(b(value(ValA),_,_),true,ValB,true,_TA,NExpr) :- |
| 1055 | | % both are FullyKnown |
| 1056 | | simple_value(ValA), % we should avoid closures |
| 1057 | | !, |
| 1058 | | kernel_equality:equality_objects(ValA,ValB,PRes), |
| 1059 | | convert_pred_res(PRes,NExpr). |
| 1060 | | generate_equality_with_value(NExprA,_,Value,_,TA,equal(NExprA,b(value(Value),TA,[]))). |
| 1061 | | |
| 1062 | | % similar to custom_explicit_sets:simple_value |
| 1063 | | % values where we can decide equality easily |
| 1064 | | simple_value(fd(_,_)). |
| 1065 | | simple_value(pred_true /* bool_true */). |
| 1066 | | simple_value(pred_false /* bool_false */). |
| 1067 | | simple_value(int(_)). |
| 1068 | | simple_value((A,B)) :- simple_value(A), simple_value(B). |
| 1069 | | simple_value(rec(Fields)) :- maplist(simple_field,Fields). |
| 1070 | | simple_value(string(_)). |
| 1071 | | |
| 1072 | | simple_field(field(_,Val)) :- simple_value(Val). |
| 1073 | | |
| 1074 | | known_value(X,FullyKnown) :- (known_value(X) -> FullyKnown=true ; FullyKnown=false). |
| 1075 | | known_value(X) :- nonvar(X), known_value2(X). |
| 1076 | | known_value2(global_set(GS)) :- nonvar(GS). |
| 1077 | | known_value2(freetype(GS)) :- nonvar(GS). |
| 1078 | | known_value2(closure(P,T,B)) :- known_closure(P,T,B). |
| 1079 | | %Note: for other closures: they still may have to be computed; some of the computations in wd_and_efficient could be expensive for closures |
| 1080 | | known_value2(avl_set(_)). % already fully normalised |
| 1081 | | known_value2((X,Y)) :- known_value(X),known_value(Y). |
| 1082 | | known_value2(fd(A,B)) :- number(A),atomic(B). |
| 1083 | | known_value2(int(N)) :- number(N). |
| 1084 | | known_value2([]). |
| 1085 | | known_value2(pred_true). |
| 1086 | | known_value2(pred_false). |
| 1087 | | known_value2(string(S)) :- atomic(S). |
| 1088 | | known_value2([H|T]) :- known_value(H), known_value(T). |
| 1089 | | %known_value2(record(Fields)) :- known_fields(Fields). |
| 1090 | | known_value2(rec(Fields)) :- known_fields(Fields). |
| 1091 | | |
| 1092 | | :- use_module(avl_tools,[avl_height_less_than/2]). |
| 1093 | | % large known avl_set value; for issueing perfmessage warnings |
| 1094 | | large_known_value(b(value(V),_,_),Lim) :- nonvar(V), large_known_aux(V,Lim). |
| 1095 | | large_known_aux(avl_set(A),Lim) :- |
| 1096 | | \+ avl_height_less_than(A,Lim). |
| 1097 | | |
| 1098 | | % something we could do: |
| 1099 | | %optimize_known_value([H|T],Res) :- (convert_to_avl([H|T],CS) -> Res=CS ; print(failed_to_convert_known_list),nl,fail). |
| 1100 | | % try_convert_to_avl |
| 1101 | | |
| 1102 | | known_closure(P,T,B) :- custom_explicit_sets:is_interval_closure(P,T,B,Low,Up), !, |
| 1103 | | number(Low), number(Up), |
| 1104 | | Up < Low+1000. |
| 1105 | | known_closure(P,T,B) :- |
| 1106 | | is_cartesian_product_closure(closure(P,T,B),A1,A2), |
| 1107 | | !,% we could call is_cartesian_product_closure_aux(P,T,B,A1,A2) |
| 1108 | | known_value(A1), known_value(A2). |
| 1109 | | |
| 1110 | | known_fields(X) :- var(X),!,fail. |
| 1111 | | known_fields([]). |
| 1112 | | known_fields([field(N,V)|T]) :- ground(N),known_value(V),known_fields(T). |
| 1113 | | |
| 1114 | | %b_evaluate1(TExpr,Parameters,LS,S,ResultTExpr,FullyKnown) :- |
| 1115 | | |
| 1116 | | check_is_id_list([],[]). |
| 1117 | | check_is_id_list([H|T],Res) :- |
| 1118 | | (H=b(identifier(_),_,_) |
| 1119 | | -> 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) |
| 1120 | | maplist(def_get_texpr_id,[H|T],Res) |
| 1121 | | ; Res=[H|T]). |
| 1122 | | |
| 1123 | | :- use_module(kernel_frozen_info,[kfi_domain/2]). |
| 1124 | | |
| 1125 | | :- use_module(custom_explicit_sets,[construct_interval_closure/3]). |
| 1126 | | % try and evaluate domain of a list (avl_set already dealt with separately) |
| 1127 | | %evaluate_domain(X,_) :- print(dom(X)),nl,fail. |
| 1128 | | evaluate_domain(sequence_extension(L),Domain) :- length(L,Len), |
| 1129 | | % this will prevent computing range of sequence extension: can hide WD issues ! TO DO: check wd info and/or preference |
| 1130 | | construct_interval_closure(1,Len,Domain). |
| 1131 | | % TO DO: set_extension when possible ? |
| 1132 | | evaluate_domain(value(L),Domain) :- |
| 1133 | | get_domain(L,Domain). |
| 1134 | | |
| 1135 | | get_domain(V,Dom) :- var(V),!,kfi_domain(V,Dom). % try infer domain from attached co-routines |
| 1136 | | get_domain([],[]). |
| 1137 | | get_domain([V|VT],Result) :- nonvar(V), V=(D,_), |
| 1138 | | known_value(D),get_list_domain(VT,DT), |
| 1139 | | %length(DT,Len),print(got_list_domain(D,Len)),nl, |
| 1140 | | (custom_explicit_sets:try_convert_to_avl([D|DT],Res) -> Result=Res |
| 1141 | | ; write(could_not_convert_domain_to_avl(D)),nl, Result=[D|DT]). %sort([D|DT],Result)? |
| 1142 | | % we could also do this: |
| 1143 | | %get_domain(closure(Par,Typ,Body),Result) :- |
| 1144 | | % is_lambda_value_domain_closure(Par,Typ,Body, DomainValue,Expr), check_wd(Expr), |
| 1145 | | % Result=DomainValue. |
| 1146 | | get_list_domain(V,_) :- var(V),!,fail. |
| 1147 | | get_list_domain([],[]). |
| 1148 | | get_list_domain([V|VT],[D|DT]) :- nonvar(V), V=(D,_), |
| 1149 | | known_value(D),get_list_domain(VT,DT). |
| 1150 | | |
| 1151 | | |
| 1152 | | :- use_module(kernel_frozen_info,[kfi_range/2]). |
| 1153 | | |
| 1154 | | % try and evaluate range of a list (avl_set already dealt with separately) |
| 1155 | | evaluate_range(b(value(L),_T,_),Range) :- |
| 1156 | | get_range(L,Range). |
| 1157 | | get_range(V,Dom) :- var(V),!,kfi_range(V,Dom). % try infer range from attached co-routines |
| 1158 | | get_range([],[]). |
| 1159 | | get_range([V|VT],Result) :- nonvar(V), V=(_,D), |
| 1160 | | known_value(D), |
| 1161 | | get_list_range(VT,DT), |
| 1162 | | sort([D|DT],Result). |
| 1163 | | |
| 1164 | | get_list_range(V,_) :- var(V),!,fail. |
| 1165 | | get_list_range([],[]). |
| 1166 | | get_list_range([V|VT],[D|DT]) :- |
| 1167 | | nonvar(V), V=(_,D), |
| 1168 | | known_value(D), |
| 1169 | | get_list_range(VT,DT). |
| 1170 | | |
| 1171 | | create_equality_for_let(LHS,RHS,Conj) :- |
| 1172 | | maplist(create_eq,LHS,RHS,CL), |
| 1173 | | conjunct_predicates(CL,Conj). |
| 1174 | | create_eq(Id,Expr,TPred) :- safe_create_texpr(equal(Id,Expr),pred,TPred). |
| 1175 | | |
| 1176 | | % split formal operation call parameters into those which clash and those that do not: |
| 1177 | | split_formal_parameters([],[],_,[],[],[],[]). |
| 1178 | | split_formal_parameters([Formal1|FormalT],[Val1|VT],LocalKnownParas,Fresh,FV,Clash,CV) :- |
| 1179 | ? | (id_clash(LocalKnownParas,Formal1) |
| 1180 | | -> Fresh = FreshT, FV=FVT, Clash = [Formal1|ClashT], CV = [Val1|CVT] |
| 1181 | | ; Fresh = [Formal1|FreshT], FV = [Val1|FVT], Clash = ClashT, CV = CVT |
| 1182 | | ), split_formal_parameters(FormalT,VT,LocalKnownParas,FreshT,FVT,ClashT,CVT). |
| 1183 | | |
| 1184 | | :- use_module(gensym,[gensym/2]). |
| 1185 | | create_fresh_id(b(identifier(_),T,I),b(identifier(FRESHID),T,I)) :- |
| 1186 | | gensym('__COMPILED_ID__',FRESHID). |
| 1187 | | |
| 1188 | | :- use_module(bsyntaxtree, [get_texpr_pos/2,same_id/3]). |
| 1189 | | % compute which assignments are really necessary, remove skip assignments x := x |
| 1190 | | simplify_assignment([],[],[],[]). |
| 1191 | | simplify_assignment([ID1|T1],[ID2|T2],Res1,Res2) :- |
| 1192 | | (same_id(ID1,ID2,_) -> Res1=TR1, Res2=TR2 ; Res1=[ID1|TR1], Res2=[ID2|TR2]), |
| 1193 | | simplify_assignment(T1,T2,TR1,TR2). |
| 1194 | | |
| 1195 | | |
| 1196 | | /* |
| 1197 | | % check if an AST term is a total lambda without WD condition: |
| 1198 | | % NExprA=value(closure([x,...,'_lambda_result_'],b(equal())), NExprB=couple(,,,,) -> replace x by parameters |
| 1199 | | % possibly better to do this via contains_wd_condition or similar Info field?! |
| 1200 | | |
| 1201 | | |
| 1202 | | is_total_lambda(b(value(V),_,_),OtherIDs,LambdaExpr) :- nonvar(V), |
| 1203 | | V=closure(Args,_Types,Body), |
| 1204 | | is_total_lambda_closure(Args,Body, OtherIDs, LambdaExpr). |
| 1205 | | |
| 1206 | | :- use_module(probsrc(bsyntaxtree),[conjunction_to_list/2,occurs_in_expr/2]). |
| 1207 | | is_total_lambda_closure(Args,b(equal(TLambda,LambdaExpr),pred,_),OtherIDs,LambdaExpr) :- |
| 1208 | | get_texpr_id(TLambda,LambdaID), |
| 1209 | | append(OtherIDs,[LambdaID],Args), |
| 1210 | | \+ occurs_in_expr(LambdaID,LambdaExpr). |
| 1211 | | |
| 1212 | | % try and get arguments from expression |
| 1213 | | get_actual_arguments([_],Expr,Args) :- !, |
| 1214 | | % print('arg1: '),tools_printing:print_term_summary(Expr),nl, |
| 1215 | | check_simple(Expr), |
| 1216 | | Args= [Expr]. |
| 1217 | | get_actual_arguments([_|T],b(Couple,_,_),[Arg1|TArgs]) :- |
| 1218 | | get_couple(Couple,Arg1,Arg2), print('arg: '),tools_printing:print_term_summary(Arg1),nl, |
| 1219 | | check_simple(Arg1), |
| 1220 | | get_actual_arguments(T,Arg2,TArgs). |
| 1221 | | |
| 1222 | | check_simple(b(V,_,_)) :- simple2(V). |
| 1223 | | simple2(value(_)). |
| 1224 | | simple2(identifier(_)). |
| 1225 | | simple2(integer(_)). |
| 1226 | | |
| 1227 | | get_couple(couple(A,B),A,B). |
| 1228 | | %get_couple(value(V),A,B) :- nonvar(V), V=(V1,V2), ... % TODO |
| 1229 | | |
| 1230 | | |
| 1231 | | Code for bcompile2(function(...)) |
| 1232 | | |
| 1233 | | |
| 1234 | | % ; is_total_lambda(NExprA,Ids,Expr) , |
| 1235 | | % get_actual_arguments(Ids,NExprB,Args) %, print(ok),nl, translate:l_print_bexpr_or_subst(Args),nl |
| 1236 | | % -> |
| 1237 | | % bsyntaxtree:replace_ids_by_exprs(Expr,Ids,Args,Result), |
| 1238 | | % % only ok if we do not replicate expressions !! we could repeatedly re-apply rule / compilation on result |
| 1239 | | % print(' replaced: '),translate:print_bexpr(Result),nl, |
| 1240 | | % Result = b(NExpr,_,_), FullyKnown = FullyKnown12 |
| 1241 | | |
| 1242 | | */ |