| 1 | % (c) 2009-2025 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 | :- module(ast_cleanup_for_smt, [smt_clean_up/2, | |
| 6 | smt_clean_up/3, | |
| 7 | smt_clean_up/4, | |
| 8 | smt_clean_up_opts/4, | |
| 9 | smt_clean_up_pre/4, | |
| 10 | smt_clean_up_post/4]). | |
| 11 | ||
| 12 | :- use_module(library(lists),[maplist/3, | |
| 13 | append/2, | |
| 14 | is_list/1]). | |
| 15 | :- use_module(library(avl), [avl_to_list/2]). | |
| 16 | :- use_module(probsrc(bsyntaxtree),[is_texpr/1, | |
| 17 | add_texpr_infos/3, | |
| 18 | remove_bt/4, | |
| 19 | safe_create_texpr/4, | |
| 20 | create_texpr/4, | |
| 21 | get_texpr_expr/2, | |
| 22 | get_texpr_type/2, | |
| 23 | create_negation/2, | |
| 24 | conjunct_predicates/2, | |
| 25 | disjunct_predicates/2, | |
| 26 | create_forall/3, | |
| 27 | create_exists/3, | |
| 28 | create_implication/3, | |
| 29 | conjunction_to_list/2, | |
| 30 | %create_couple/2, | |
| 31 | syntaxtransformation/5, | |
| 32 | unique_typed_id/3, | |
| 33 | find_typed_identifier_uses/3, | |
| 34 | %always_well_defined_or_disprover_mode/1, | |
| 35 | is_pow_subset/2, is_pow1_subset/2, | |
| 36 | %get_integer/2, | |
| 37 | is_just_type/1]). | |
| 38 | :- use_module(probsrc(solver_interface),[solve_predicate/3]). | |
| 39 | :- use_module(probsrc(custom_explicit_sets),[is_interval_closure/3]). | |
| 40 | :- use_module(probsrc(b_interpreter_components),[extract_equalities_in_quantifier/4]). | |
| 41 | :- use_module(probsrc(error_manager), [add_internal_error/2,add_error_fail/3,add_message/2,add_message/3]). | |
| 42 | :- use_module(probsrc(debug), [debug_println/2]). | |
| 43 | :- use_module(probsrc(bsyntaxtree), [find_identifier_uses/3,find_typed_identifier_uses/2]). | |
| 44 | :- use_module(probsrc(b_global_sets), [unfixed_deferred_set/1]). | |
| 45 | :- use_module(probsrc(b_compiler), [b_compile/6]). | |
| 46 | :- use_module(probsrc(preferences), [get_preference/2,temporary_set_preference/2,reset_temporary_preference/1]). | |
| 47 | :- use_module(probsrc(store),[normalise_value_for_var/4]). | |
| 48 | :- use_module(smt_solvers_interface(quantifier_instantiation)). | |
| 49 | :- use_module(smt_solvers_interface(smt_common_predicates)). | |
| 50 | :- use_module(smt_solvers_interface(ast_optimizer_for_smt)). | |
| 51 | :- use_module(smt_solvers_interface(seq_rewriter)). | |
| 52 | :- use_module(smt_solvers_interface(set_rewriter)). | |
| 53 | :- use_module(cdclt_solver('cdclt_pred_to_sat'), [predicate_to_sat/6]). | |
| 54 | :- use_module(extension('banditfuzz/welldef')). | |
| 55 | :- use_module(probsrc('well_def/well_def_analyser'), [analyse_wd_for_expr/3]). | |
| 56 | :- use_module(probsrc('debug'), [set_silent_mode/1]). | |
| 57 | ||
| 58 | :- use_module(probsrc(module_information),[module_info/2]). | |
| 59 | :- module_info(group,smt_solvers). | |
| 60 | :- module_info(description,'This module implements transformations needed by the SMT-LIB translation.'). | |
| 61 | ||
| 62 | :- set_prolog_flag(double_quotes, codes). | |
| 63 | ||
| 64 | :- dynamic translation_type/1. | |
| 65 | ||
| 66 | %% smt_clean_up(+Ast, -Out). | |
| 67 | smt_clean_up(Ast, Out) :- | |
| 68 | smt_clean_up(axiomatic, Ast, Out). | |
| 69 | ||
| 70 | %% smt_clean_up_opts(+TranslationType, +Ast, +Options, -Out). | |
| 71 | % Cleanup without global state using Options instantiate_quantifier_limit(L). | |
| 72 | smt_clean_up_opts(TranslationType, Ast, Options, Out) :- | |
| 73 | smt_clean_up_pre(Ast, [], Options, CAst), | |
| 74 | smt_clean_up_post(TranslationType, CAst, Options, Out). | |
| 75 | ||
| 76 | %% smt_clean_up(+TranslationType, +Ast, -Out). | |
| 77 | % Cleanup without global state. | |
| 78 | smt_clean_up(TranslationType, Ast, Out) :- | |
| 79 | smt_clean_up_pre(Ast, [], [], CAst), | |
| 80 | smt_clean_up_post(TranslationType, CAst, [], Out). | |
| 81 | ||
| 82 | %% smt_clean_up(+TranslationType, +Ast, +ProBState, -Out). | |
| 83 | % Cleanup with global state. | |
| 84 | smt_clean_up(TranslationType, Ast, ProBState, Out) :- | |
| 85 | smt_clean_up_pre(Ast, ProBState, [], CAst), | |
| 86 | smt_clean_up_post(TranslationType, CAst, [], Out). | |
| 87 | ||
| 88 | get_ids_not_in_state([], _, Acc, Acc). | |
| 89 | get_ids_not_in_state([IdName|T], State, Acc, IdsNotInState) :- | |
| 90 | ( ( | |
| 91 | member(bind(IdName,_), State), | |
| 92 | \+ unfixed_deferred_set(IdName) | |
| 93 | ) | |
| 94 | -> get_ids_not_in_state(T, State, Acc, IdsNotInState) | |
| 95 | ; get_ids_not_in_state(T, State, [IdName|Acc], IdsNotInState) | |
| 96 | ). | |
| 97 | ||
| 98 | %% smt_clean_up_pre(+Ast, +ProBState, +Options, -CleanAst). | |
| 99 | % Cleanup without internal rewriting rules and independent of any translation type. | |
| 100 | % WD conditions are added if the input is not well-defined. | |
| 101 | smt_clean_up_pre(Ast, ProBState, _Options, CleanAst) :- | |
| 102 | reset_optimizer_state, | |
| 103 | ( get_preference(add_wd_pos_for_z3, true) | |
| 104 | -> % this prints missing wd conditions | |
| 105 | set_silent_mode(on), | |
| 106 | analyse_wd_for_expr(Ast, _ResStr, TIsWd), | |
| 107 | ( ground(TIsWd) | |
| 108 | -> IsWd = TIsWd | |
| 109 | ; IsWd = 'FALSE' | |
| 110 | ), | |
| 111 | set_silent_mode(off) | |
| 112 | ; IsWd = 'TRUE' | |
| 113 | ), | |
| 114 | ? | rewrite_seq_to_set(IsWd, Ast, AstWithoutSeq), |
| 115 | welldef:filter_typing_pos(true), | |
| 116 | welldef:preprocess_pos_for_cdclt(false), | |
| 117 | ( IsWd == 'TRUE' | |
| 118 | -> WDPred = AstWithoutSeq | |
| 119 | ; ensure_wd(AstWithoutSeq, WDPred), | |
| 120 | ( AstWithoutSeq \= WDPred | |
| 121 | -> add_message(smt_clean_up_pre, 'Input not well-defined: automatically added WD POs') | |
| 122 | ; true | |
| 123 | ) | |
| 124 | ), | |
| 125 | find_typed_identifier_uses(WDPred, TypedIds), | |
| 126 | ? | assert_state_id_values(TypedIds, ProBState), |
| 127 | assert_ground_id_values(0, WDPred), | |
| 128 | replace_ids_with_ground_values(WDPred, 0, [], AstGroundOpt), | |
| 129 | precompute_values_non_recursive([instantiate_quantifier_limit(0),instantiate_sets_limit(1000)], AstGroundOpt, AstGroundOpt2), | |
| 130 | find_identifier_uses(AstGroundOpt2, [], UsedIds), | |
| 131 | get_ids_not_in_state(UsedIds, ProBState, [], IdsNotInState), | |
| 132 | temporary_set_preference(data_validation_mode, true), | |
| 133 | catch(b_compile(AstGroundOpt2, IdsNotInState, ProBState, ProBState, AstOpt, no_wf_available), | |
| 134 | enumeration_warning(_,_,_,_,_), % cancel if enumeration warning has occurred | |
| 135 | AstOpt = AstGroundOpt2), | |
| 136 | reset_temporary_preference(data_validation_mode), | |
| 137 | temporary_set_preference(allow_improving_wd_mode, true), | |
| 138 | b_ast_cleanup:clean_up(AstOpt, [], TCleanAst), !, | |
| 139 | reset_temporary_preference(allow_improving_wd_mode), | |
| 140 | CleanAst = TCleanAst. | |
| 141 | ||
| 142 | %% smt_clean_up_post(+TranslationType, +CleanAst, +Options, -Out). | |
| 143 | % Cleanup with translation type specific internal rewriting rules. | |
| 144 | smt_clean_up_post(TranslationType, CleanAst, Options, Out) :- | |
| 145 | atom(TranslationType), | |
| 146 | retractall(translation_type(_)), | |
| 147 | asserta(translation_type(TranslationType)), | |
| 148 | internal_clean_up(CleanAst, TOut), | |
| 149 | reset_optimizer_state, !, | |
| 150 | ( ( memberchk(instantiate_quantifier_limit(IQLIMIT), Options), | |
| 151 | IQLIMIT > 0 | |
| 152 | ) | |
| 153 | -> instantiate_quantifiers([instantiate_quantifier_limit(IQLIMIT),not_instantiate_unfixed_deferred_sets], TOut, Out) | |
| 154 | ; Out = TOut | |
| 155 | ). | |
| 156 | ||
| 157 | internal_clean_up(ExprWithoutSeq,Out) :- | |
| 158 | clean_up(ExprWithoutSeq,CExpr,[],AC,IDs), | |
| 159 | !, | |
| 160 | combine_pred_and_ac(CExpr,AC,IDs,Out). | |
| 161 | ||
| 162 | clean_up(Expr,CExprOut,Path,ACOut,IDsOut) :- | |
| 163 | cleanups(pre,Expr,[],TPExpr,Path,ACPre,IDsPre), | |
| 164 | remove_bt(TPExpr,PExpr,LExpr,TLExpr), | |
| 165 | syntaxtransformation(PExpr,Subs,_,NewSubs,LExpr), | |
| 166 | functor(PExpr,F,N), | |
| 167 | % recursively clean up sub-expressions | |
| 168 | maplist(internal_clean_up,ACPre,ACPreClean), | |
| 169 | clean_up_l(Subs,NewSubs,F/N,1,Path,ACL,IDsL), | |
| 170 | maplist(internal_clean_up,ACL,ACLClean), | |
| 171 | cleanups(post,TLExpr,[],CExpr,Path,ACPost,IDsPost), | |
| 172 | maplist(internal_clean_up,ACPost,ACPostClean), | |
| 173 | append([ACPreClean,ACLClean,ACPostClean],AC), | |
| 174 | append([IDsPre,IDsL,IDsPost],IDs), | |
| 175 | (AC \= [], get_texpr_type(CExpr,pred) | |
| 176 | -> combine_pred_and_ac(CExpr,AC,IDs,CExprOut), | |
| 177 | % the accumulator contains additional constraints and new existentially quantified vars IDs | |
| 178 | IDsOut = [], ACOut = [] | |
| 179 | ; CExprOut = CExpr, ACOut = AC, IDsOut = IDs). | |
| 180 | ||
| 181 | combine_pred_and_ac(Pred,AC,IDs,Out) :- | |
| 182 | conjunct_predicates(AC,ACPred), | |
| 183 | conjunct_predicates([Pred,ACPred],OutInnerPred), | |
| 184 | extract_equalities_in_quantifier(IDs,OutInnerPred,I2,P2), % used in create_and_simplify_exists; can be expensive | |
| 185 | create_exists(I2,P2,Out). % TO DO: use more intelligence from create_exists_opt or similar?? | |
| 186 | ||
| 187 | clean_up_l([],[],_Functor,_Nr,_Path,[],[]). | |
| 188 | clean_up_l([Expr|Rest],[CExpr|CRest],Functor,ArgNr,Path,AC,IDs) :- | |
| 189 | clean_up(Expr,CExpr,[arg(Functor,ArgNr)|Path],ACC,IDsC), | |
| 190 | A1 is ArgNr+1, | |
| 191 | clean_up_l(Rest,CRest,Functor,A1,Path,ACL,IDsL), | |
| 192 | append(ACC,ACL,AC), | |
| 193 | append(IDsC,IDsL,IDs). | |
| 194 | ||
| 195 | cleanups(Phase,Expr,AppliedRules,Result,Path,ACS,IDs) :- | |
| 196 | start_profile_rule(RuleInfos), | |
| 197 | assure_single_rules(AppliedRules,Rule), | |
| 198 | ? | ( cleanup_phase(Phase,Expr,NExpr,Mode/Rule,Path,ACPhase,IDsPhase) |
| 199 | -> % try to apply a rule (matching the current phase) | |
| 200 | ( Mode == single | |
| 201 | -> AppRules = [Rule|AppliedRules] % if the rule is marked as "single", we add to the list of already applied rules | |
| 202 | ; Mode == multi | |
| 203 | -> AppRules = AppliedRules % if "multi", we do not add it to the list, the rule might be applied more than once | |
| 204 | ; add_error_fail(ast_cleanup_for_smt,'Unexpected rule mode ',Mode) | |
| 205 | ), | |
| 206 | %format('Applied smt cleanup rule ~w (mode:~w)~n',[Rule,Mode]), translate:print_bexpr(NExpr),nl, | |
| 207 | stop_profile_rule(Rule,Mode,Phase,Expr,RuleInfos), | |
| 208 | cleanups(Phase,NExpr,AppRules,Result,Path,ACRec,IDsRec), % continue recursively with the new expression | |
| 209 | append(ACPhase,ACRec,ACS), | |
| 210 | append(IDsPhase,IDsRec,IDs) | |
| 211 | ; % if no rule matches anymore, | |
| 212 | stop_profile_rule(finalise,finished,Phase,Expr,RuleInfos), | |
| 213 | Result = Expr, % we leave the expression unmodified | |
| 214 | ACS = [], IDs = [], | |
| 215 | Rule = none | |
| 216 | ). % and unblock the co-routine (see assure_single_rules/2) | |
| 217 | ||
| 218 | :- if(fail). % comment in to see expensive cleanup rules | |
| 219 | start_profile_rule([R1,W1]) :- statistics(runtime,[R1,_]),statistics(walltime,[W1,_]). | |
| 220 | stop_profile_rule(Rule,Mode,Phase,Expr,[R1,W1]) :- | |
| 221 | statistics(runtime,[R2,_]),statistics(walltime,[W2,_]), | |
| 222 | DeltaW is W2-W1, DeltaR is R2-R1, | |
| 223 | (DeltaW < 20 -> true ; format('Firing SMT AST cleanup rule ~w (mode:~w) in phase ~w took ~w ms (~w ms walltime)~n',[Rule,Mode,Phase,DeltaR,DeltaW]), translate:print_span(Expr),nl), | |
| 224 | runtime_profiler:register_profiler_runtime(Rule,ast_cleanup,unknown,DeltaR,DeltaW). | |
| 225 | :- else. | |
| 226 | start_profile_rule(_). | |
| 227 | stop_profile_rule(_,_,_,_,_). | |
| 228 | :- endif. | |
| 229 | ||
| 230 | ||
| 231 | assure_single_rules([],_Rule) :- !. | |
| 232 | assure_single_rules(AppliedRules,Rule) :- | |
| 233 | assure_single_rules2(AppliedRules,Rule). | |
| 234 | :- block assure_single_rules2(?,-). | |
| 235 | assure_single_rules2(_AppliedRules,none) :- !. | |
| 236 | assure_single_rules2(AppliedRules,Rule) :- | |
| 237 | \+ member(Rule, AppliedRules). | |
| 238 | ||
| 239 | cleanup_phase(Phase,OTExpr,NTExpr,Mode/Rule,Path,AC,IDs) :- | |
| 240 | create_texpr(OExpr,OType,OInfo,OTExpr), | |
| 241 | create_texpr(NExpr,NType,NInfo,NTExpr), | |
| 242 | ? | cleanup_phase2(Phase,OExpr,OType,OInfo,NExpr,NType,NInfo,Mode/Rule,Path,AC,IDs). |
| 243 | cleanup_phase2(pre,OExpr,OType,OInfo,NExpr,NType,NInfo,Mode/Rule,_Path,AC,IDs) :- | |
| 244 | ? | cleanup_pre(OExpr,OType,OInfo,NExpr,NType,NInfo,Mode_Rule,AC,IDs), |
| 245 | (functor(Mode_Rule,'/',2) -> Mode_Rule = Mode/Rule | |
| 246 | ; add_internal_error('Illegal cleanup_pre rule, missing mode: ',Mode_Rule),fail). | |
| 247 | cleanup_phase2(post,OExpr,OType,OInfo,NExpr,NType,NInfo,Mode/Rule,Path,AC,IDs) :- | |
| 248 | cleanup_post_with_path(OExpr,OType,OInfo,NExpr,NType,NInfo,Mode_Rule,Path,AC,IDs), | |
| 249 | (functor(Mode_Rule,'/',2) | |
| 250 | -> Mode_Rule = Mode/Rule %,format(' cleanup_post Rule: ~w/~w~n',[Mode,Rule]) | |
| 251 | ; add_internal_error('Illegal cleanup_post rule, missing mode: ',Mode_Rule),fail). | |
| 252 | ||
| 253 | replace_prob_closure_record_field(field(FName,Val), NField) :- | |
| 254 | Val = closure(['_zzzz_unary'],[InnerType],_), | |
| 255 | replace_prob_closure(Val, NVal), | |
| 256 | !, | |
| 257 | NField = field(FName,b(NVal,set(InnerType),[])). | |
| 258 | ||
| 259 | replace_prob_closure(closure(['_zzzz_unary'],_,P), NExpr) :- | |
| 260 | P = b(member(b(identifier('_zzzz_unary'),_,_),ClosurePred),pred,_), | |
| 261 | find_typed_identifier_uses(ClosurePred, [], UsedIds), | |
| 262 | UsedIds == [], | |
| 263 | !, | |
| 264 | get_texpr_expr(ClosurePred, NExpr). | |
| 265 | replace_prob_closure(closure(['_zzzz_unary'],T,P), value(ComputedVal)) :- | |
| 266 | normalise_value_for_var(solver_result, force, closure(['_zzzz_unary'],T,P), ComputedVal), | |
| 267 | ComputedVal \== closure(['_zzzz_unary'],T,P). | |
| 268 | ||
| 269 | % enforce well-definedness of division | |
| 270 | cleanup_pre(div(A,B),integer,I,div(A,B),integer,[smt_wd_added|I],multi/div_wd,[AC],[]) :- | |
| 271 | \+ member(smt_wd_added,I), !, | |
| 272 | create_texpr(not_equal(B,b(integer(0),integer,[])),pred,[],AC). | |
| 273 | % replace not_equal(..) by not(equal(..)) | |
| 274 | % and not_member(..) by not(member(..)) | |
| 275 | % and not_subset_strict(..) by not(subset_strict(..)) | |
| 276 | % and not_subset(..) by subset(..) | |
| 277 | cleanup_pre(value(closure(['_zzzz_unary'],T,P)),Type,I,Expr,Type,I,multi/rewrite_prob_closure,[],[]) :- | |
| 278 | replace_prob_closure(closure(['_zzzz_unary'],T,P), Expr). | |
| 279 | cleanup_pre(union(A,B),Type,_,reflexive_closure(Rel),Type,I,multi/replace_not_equal,[],[]) :- | |
| 280 | A = b(event_b_identity,_,_), | |
| 281 | B = b(closure(Rel),Type,I). | |
| 282 | cleanup_pre(not_equal(A,B),pred,I,negation(Equal),pred,[],multi/replace_not_equal,[],[]) :- | |
| 283 | create_texpr(equal(A,B),pred,I,Equal). | |
| 284 | cleanup_pre(not_member(A,B),pred,I,negation(Member),pred,[],multi/replace_not_member,[],[]) :- | |
| 285 | create_texpr(member(A,B),pred,I,Member). | |
| 286 | cleanup_pre(not_subset_strict(A,B),pred,I,negation(Subset),pred,[],multi/replace_not_subset_strict,[],[]) :- | |
| 287 | create_texpr(subset_strict(A,B),pred,I,Subset). | |
| 288 | cleanup_pre(greater(Card,Integer0),pred,I,Res,pred,I,multi/replace_card_0_with_neq_empty,[],[]) :- | |
| 289 | % card(S) > 0 --> S /= {} | |
| 290 | Card = b(card(Set),integer,_), | |
| 291 | (Integer0 = b(integer(0),integer,_); Integer0 = b(value(int(0)),integer,_)), | |
| 292 | !, | |
| 293 | get_texpr_type(Set, SetType), | |
| 294 | Res = not_equal(Set,b(empty_set,SetType,[])). | |
| 295 | cleanup_pre(less(Integer0,Card),pred,I,Res,pred,I,multi/replace_card_0_with_neq_empty,[],[]) :- | |
| 296 | % 0 < card(S) --> S /= {} | |
| 297 | Card = b(card(Set),integer,_), | |
| 298 | (Integer0 = b(integer(0),integer,_); Integer0 = b(value(int(0)),integer,_)), | |
| 299 | !, | |
| 300 | get_texpr_type(Set, SetType), | |
| 301 | Res = not_equal(Set,b(empty_set,SetType,[])). | |
| 302 | cleanup_pre(not_equal(Card,Integer0),pred,I,Res,pred,I,multi/replace_card_0_with_neq_empty,[],[]) :- | |
| 303 | % card(S) /= 0 --> S /= {} | |
| 304 | Card = b(card(Set),integer,_), | |
| 305 | (Integer0 = b(integer(0),integer,_); Integer0 = b(value(int(0)),integer,_)), | |
| 306 | !, | |
| 307 | get_texpr_type(Set, SetType), | |
| 308 | Res = not_equal(Set,b(empty_set,SetType,[])). | |
| 309 | cleanup_pre(not_equal(Integer0,Card),pred,I,Res,pred,I,multi/replace_card_0_with_neq_empty,[],[]) :- | |
| 310 | % 0 /= card(S) --> S /= {} | |
| 311 | Card = b(card(Set),integer,_), | |
| 312 | (Integer0 = b(integer(0),integer,_); Integer0 = b(value(int(0)),integer,_)), | |
| 313 | !, | |
| 314 | get_texpr_type(Set, SetType), | |
| 315 | Res = not_equal(Set,b(empty_set,SetType,[])). | |
| 316 | cleanup_pre(equal(Card,Integer0),pred,I,Res,pred,I,multi/replace_card_0_with_eq_empty,[],[]) :- | |
| 317 | % card(S) = 0 --> S = {} | |
| 318 | Card = b(card(Set),integer,_), | |
| 319 | (Integer0 = b(integer(0),integer,_); Integer0 = b(value(int(0)),integer,_)), | |
| 320 | !, | |
| 321 | get_texpr_type(Set, SetType), | |
| 322 | Res = equal(Set,b(empty_set,SetType,[])). | |
| 323 | cleanup_pre(equal(Integer0,Card),pred,I,Res,pred,I,multi/replace_card_0_with_eq_empty,[],[]) :- | |
| 324 | % 0 = card(S) --> S = {} | |
| 325 | Card = b(card(Set),integer,_), | |
| 326 | (Integer0 = b(integer(0),integer,_); Integer0 = b(value(int(0)),integer,_)), | |
| 327 | !, | |
| 328 | get_texpr_type(Set, SetType), | |
| 329 | Res = equal(Set,b(empty_set,SetType,[])). | |
| 330 | cleanup_pre(FiniteCardConstraint,pred,I,Res,pred,I,multi/RuleDescr,[],[]) :- | |
| 331 | rewrite_finite_card(FiniteCardConstraint, Res, RuleDescr). | |
| 332 | cleanup_pre(member(A,B),pred,I,Out,pred,I,multi/replace_member_interval,[],[]) :- | |
| 333 | is_interval(B,Low,Up), | |
| 334 | !, % A:Low..Up <==> A>=Low & A<=Up % important for e.g. :z3-cns mxint = 500 & goal : -mxint ..mxint | |
| 335 | Out = conjunct(b(greater_equal(A,Low),pred,[]),b(greater_equal(Up,A),pred,[])). | |
| 336 | cleanup_pre(member(A,B),pred,I,Out,pred,I,multi/replace_member_pow1_or_fin1,[],[]) :- | |
| 337 | is_pow1_subset(B,Set), | |
| 338 | get_texpr_type(Set, SetType), | |
| 339 | !, % A:POW1(Set) <==> A <: Set & A /= {} | |
| 340 | Out = conjunct(b(subset(A,Set),pred,[]),b(not_equal(A,b(set_extension([]),SetType,[])),pred,[])). | |
| 341 | cleanup_pre(member(A,B),pred,I,Out,pred,I,multi/replace_member_pow_or_fin,[],[]) :- | |
| 342 | is_pow_subset(B,Set), | |
| 343 | !, % A:POW(Set) <==> A <: Set | |
| 344 | % A/:POW(Set) <==> A /<: Set ; does not really seem to be necessary as negation rewritten before | |
| 345 | Out = subset(A,Set). | |
| 346 | cleanup_pre(member(A,B),pred,I,Disj,pred,I,multi/replace_finite_member_by_disj,[],[]) :- | |
| 347 | % rewrite finite set membership to disjunction of equalities | |
| 348 | B = b(value(avl_set(AvlSet)),set(InnerType),_), | |
| 349 | !, | |
| 350 | avl_to_list(AvlSet, EnumValueList), | |
| 351 | findall(Equality, (member(EnumValue-_, EnumValueList), Equality = b(equal(A,b(value(EnumValue),InnerType,[])),pred,[])), Equalities), | |
| 352 | disjunct_predicates(Equalities, DisjAst), | |
| 353 | DisjAst = b(Disj,_,_). | |
| 354 | cleanup_pre(not_subset(A,B),pred,I,negation(Subset),pred,[],multi/replace_not_subset,[],[]) :- | |
| 355 | create_texpr(subset(A,B),pred,I,Subset). | |
| 356 | % replace subset_strict by subset and not_equal | |
| 357 | cleanup_pre(subset_strict(A,B),pred,I,conjunct(NotEqual,Subset),pred,[],multi/replace_not_member,[],[]) :- | |
| 358 | create_texpr(subset(A,B),pred,I,Subset), | |
| 359 | create_texpr(not_equal(A,B),pred,I,NotEqual). | |
| 360 | cleanup_pre(equal(R,S),pred,I,POut,pred,I,multi/replace_struct_equality,[],[]) :- | |
| 361 | % e.g., rewrite Dom = struct(f1:{1,2},f2:{1,2}) to Dom = {rec(f1:1,f2:1),rec(f1:1,f2:2),rec(f1:2,f2:1),rec(f1:2,f2:2)} | |
| 362 | S = b(value(closure(['_zzzz_unary'],[record(_)],_)),_,_), | |
| 363 | get_texpr_expr(R, identifier(IdName)), | |
| 364 | get_texpr_type(R, set(record(FieldTypes))), | |
| 365 | solver_interface:solve_predicate(b(equal(R,S),pred,I), Bindings, _), | |
| 366 | member(bind(IdName,Set), Bindings), | |
| 367 | % only for finite records | |
| 368 | Set \= closure(_,_,_), | |
| 369 | !, | |
| 370 | POut = equal(R,b(value(Set),set(record(FieldTypes)),[])). | |
| 371 | % replace membership in struct by equalities to avoid powerset construction | |
| 372 | cleanup_pre(member(R,S),pred,I,POut,pred,I,multi/replace_struct_membership,[],[]) :- | |
| 373 | % rewrite ProB closures introduced by b_compile/6 | |
| 374 | get_texpr_expr(R,identifier(_)), | |
| 375 | S = b(value(ProBClosure),_,_), | |
| 376 | replace_prob_closure(ProBClosure, ClosureExpr), | |
| 377 | ClosureExpr = struct(Proto), | |
| 378 | Proto = b(value(rec(Fields)),_,_), | |
| 379 | ( maplist(replace_prob_closure_record_field, Fields, TFields) | |
| 380 | -> NFields = TFields | |
| 381 | ; NFields = Fields | |
| 382 | ), | |
| 383 | !, | |
| 384 | maplist(rewrite_struct_ids(R),NFields,Constraints), | |
| 385 | conjunct_predicates(Constraints,Conj), | |
| 386 | get_texpr_expr(Conj,POut). | |
| 387 | cleanup_pre(member(R,S),pred,I,POut,pred,I,multi/replace_struct_membership,[],[]) :- | |
| 388 | get_texpr_expr(R,identifier(_)), | |
| 389 | get_texpr_expr(S,struct(Proto)), | |
| 390 | get_texpr_expr(Proto,value(rec(Fields))), | |
| 391 | maplist(rewrite_struct_ids(R),Fields,Constraints), | |
| 392 | conjunct_predicates(Constraints,Conj), | |
| 393 | get_texpr_expr(Conj,POut). | |
| 394 | cleanup_pre(member(E,S),pred,I,disjunct(M1,M2),pred,I,multi/split_union_in_member,[],[]) :- | |
| 395 | get_texpr_expr(S,union(S1,S2)), | |
| 396 | create_texpr(member(E,S1),pred,I,M1), | |
| 397 | create_texpr(member(E,S2),pred,I,M2). | |
| 398 | cleanup_pre(member(E,S),pred,I,conjunct(M1,M2),pred,I,multi/split_intersection_in_member,[],[]) :- | |
| 399 | get_texpr_expr(S,intersection(S1,S2)), | |
| 400 | create_texpr(member(E,S1),pred,I,M1), | |
| 401 | create_texpr(member(E,S2),pred,I,M2). | |
| 402 | cleanup_pre(member(E,S),pred,I,conjunct(M1,NotM2),pred,I,multi/split_set_subtraction_in_member,[],[]) :- | |
| 403 | get_texpr_expr(S,set_subtraction(S1,S2)), | |
| 404 | create_texpr(member(E,S1),pred,I,M1), | |
| 405 | create_texpr(member(E,S2),pred,I,M2), | |
| 406 | create_negation(M2,NotM2). | |
| 407 | cleanup_pre(member(E,F),pred,I,C,pred,I,multi/rewrite_member_of_function,[],[]) :- | |
| 408 | %translation_type(axiomatic), | |
| 409 | ? | rewrite_member_of_function(E,F,C). |
| 410 | cleanup_pre(member(E,S),pred,I,C,pred,I,multi/rewrite_member_to_disequalities,[],[]) :- | |
| 411 | get_texpr_type(E,integer), | |
| 412 | get_texpr_type(S,set(integer)), | |
| 413 | rewrite_member_to_ge_le(E,S,C). | |
| 414 | cleanup_pre(equal(S,GlobalIntSet),pred,I,C,pred,I,multi/rewrite_equal_to_disequalities,[],[]) :- | |
| 415 | get_texpr_type(S,set(integer)), | |
| 416 | get_texpr_expr(GlobalIntSet,integer_set(_)), | |
| 417 | rewrite_equal_to_ge_le(S,GlobalIntSet,C). | |
| 418 | cleanup_pre(subset(Sub,Super),pred,I,C,pred,I,multi/rewrite_subset_of_integer_set_or_interval,[],[]) :- | |
| 419 | get_texpr_type(Sub,set(integer)), | |
| 420 | (get_texpr_expr(Super,integer_set(_)) ; get_texpr_expr(Super,interval(_,_))), | |
| 421 | rewrite_subset_of_integer_set(Sub,Super,C). | |
| 422 | % if there are still interval nodes after the former rule, try to replace them by constants | |
| 423 | cleanup_pre(interval(From,To),set(integer),I,NExpr,set(integer),I,multi/rewrite_constant_interval,[],[]) :- | |
| 424 | precompute_values(b(interval(From,To),set(integer),I), [instantiate_quantifier_limit(0)], Precomputed), | |
| 425 | Precomputed = b(TExpr,_,_), | |
| 426 | TExpr \= interval(From,To), | |
| 427 | !, | |
| 428 | NExpr = TExpr. | |
| 429 | % remaining intervals have to be rewritten to set comprehensions (introduced forall) | |
| 430 | cleanup_pre(interval(From,To),set(integer),I,comprehension_set([UIdD],Pred),set(integer),I,multi/rewrite_interval_to_set_comprehension,[],[]) :- | |
| 431 | translation_type(axiomatic), | |
| 432 | unique_typed_id("_smt_tmp",integer,UIdD), | |
| 433 | create_texpr(greater_equal(UIdD,From),pred,[],Pred1), | |
| 434 | create_texpr(less_equal(UIdD,To),pred,[],Pred2), | |
| 435 | conjunct_predicates([Pred1,Pred2],Pred). | |
| 436 | % rewrite some operators to set comprehensions | |
| 437 | % later rules will rewrite them again and introduce foralls | |
| 438 | cleanup_pre(pow_subset(Set),set(set(T)),I,comprehension_set([UIdD],Pred),set(set(T)),I,multi/rewrite_pow_subset,[],[]) :- | |
| 439 | translation_type(axiomatic), | |
| 440 | unique_typed_id("_smt_tmp",set(T),UIdD), | |
| 441 | create_texpr(subset(UIdD,Set),pred,[],Pred). | |
| 442 | cleanup_pre(pow1_subset(Set),set(set(T)),I,comprehension_set([UIdD],Pred),set(set(T)),I,multi/rewrite_pow1_subset,[],[]) :- | |
| 443 | translation_type(axiomatic), | |
| 444 | unique_typed_id("_smt_tmp",set(T),UIdD), | |
| 445 | create_texpr(subset(UIdD,Set),pred,[],PredSubset), | |
| 446 | create_texpr(empty_set,set(T),[],EmptySet), | |
| 447 | create_texpr(not_equal(UIdD,EmptySet),pred,[],PredNotEqual), | |
| 448 | conjunct_predicates([PredSubset,PredNotEqual],Pred). | |
| 449 | cleanup_pre(fin_subset(Set),set(set(T)),I,comprehension_set([UIdD],Pred),set(set(T)),I,multi/rewrite_fin_subset,[],[]) :- | |
| 450 | unique_typed_id("_smt_tmp",set(T),UIdD), | |
| 451 | create_texpr(subset(UIdD,Set),pred,[],Pred1), | |
| 452 | create_texpr(finite(Set),pred,[],Pred2), | |
| 453 | conjunct_predicates([Pred1,Pred2],Pred). | |
| 454 | cleanup_pre(fin1_subset(Set),set(set(T)),I,comprehension_set([UIdD],Pred),set(set(T)),I,multi/rewrite_fin1_subset,[],[]) :- | |
| 455 | unique_typed_id("_smt_tmp",set(T),UIdD), | |
| 456 | create_texpr(subset(UIdD,Set),pred,[],PredSubset), | |
| 457 | create_texpr(empty_set,set(T),[],EmptySet), | |
| 458 | create_texpr(not_equal(UIdD,EmptySet),pred,[],PredNotEqual), | |
| 459 | create_texpr(finite(Set),pred,[],PredIsFinite), | |
| 460 | conjunct_predicates([PredSubset,PredNotEqual,PredIsFinite],Pred). | |
| 461 | /*cleanup_pre(relations(SetA,SetB),Type,I,pow_subset(Cart),Type,I,multi/rewrite_relations,[],[]) :- | |
| 462 | Type = set(IT), | |
| 463 | Cart = b(cartesian_product(SetA,SetB),IT,[]). | |
| 464 | cleanup_pre(partial_function(SetA,SetB),Type,I,comprehension_set([IdR],Body),Type,I,multi/rewrite_partial_function,[],[]) :- | |
| 465 | translation_type(constructive), | |
| 466 | Type = set(set(IT)), | |
| 467 | unique_typed_id("_r", set(IT), IdR), | |
| 468 | IT = couple(TA,TB), | |
| 469 | get_texpr_type(SetB, TSetB), | |
| 470 | TSetB = set(InnerSetTypeB), | |
| 471 | Member = b(member(IdR,b(pow_subset(b(cartesian_product(SetA,SetB),set(IT),[])),set(set(IT)),[])),pred,[]), | |
| 472 | Comp = b(composition(b(reverse(IdR),set(couple(TB,TA)),[]),IdR),set(couple(InnerSetTypeB,InnerSetTypeB)),[]), | |
| 473 | Subset = b(subset(Comp,b(identity(SetB),set(couple(InnerSetTypeB,InnerSetTypeB)),[])),pred,[]), | |
| 474 | Body = b(conjunct(Member,Subset),pred,[]).*/ | |
| 475 | % TO DO: rewrite all functions? -> problems with model translation; probably not worth it though | |
| 476 | cleanup_pre(direct_product(SetA,SetB),Type,I,comprehension_set([UIdE,UIdF,UIdG],Pred),Type,I,multi/rewrite_direct_product,[],[]) :- | |
| 477 | translation_type(axiomatic), | |
| 478 | Type = set(couple(E,couple(F,G))), | |
| 479 | % TODO: the typing of the comprehension set ids creates a set of couples with a different nesting !! | |
| 480 | % {x,y,z|(x,y):a & (x,z):b} is not type compatible with a >< b | |
| 481 | % this is corrected by the translation later to quantifiers | |
| 482 | unique_typed_id("_smt_tmp",E,UIdE), | |
| 483 | unique_typed_id("_smt_tmp",F,UIdF), | |
| 484 | unique_typed_id("_smt_tmp",G,UIdG), | |
| 485 | create_texpr(couple(UIdE,UIdF),couple(E,F),[],CEF), | |
| 486 | create_texpr(couple(UIdE,UIdG),couple(E,G),[],CEG), | |
| 487 | create_texpr(member(CEF,SetA),pred,[],M1), | |
| 488 | create_texpr(member(CEG,SetB),pred,[],M2), | |
| 489 | conjunct_predicates([M1,M2],Pred). | |
| 490 | cleanup_pre(parallel_product(SetA,SetB),Type,I,comprehension_set([UIdE,UIdG,UIdF,UIdH],Pred),Type,I,multi/rewrite_parallel_product,[],[]) :- | |
| 491 | translation_type(axiomatic), | |
| 492 | Type = set(couple(couple(E,G),couple(F,H))), | |
| 493 | % TODO: the typing of the comprehension set ids creates a set of couples with a different nesting !! | |
| 494 | unique_typed_id("_smt_tmp",E,UIdE), | |
| 495 | unique_typed_id("_smt_tmp",F,UIdF), | |
| 496 | unique_typed_id("_smt_tmp",G,UIdG), | |
| 497 | unique_typed_id("_smt_tmp",H,UIdH), | |
| 498 | create_texpr(couple(UIdE,UIdF),couple(E,F),[],CEF), | |
| 499 | create_texpr(couple(UIdG,UIdH),couple(G,H),[],CGH), | |
| 500 | create_texpr(member(CEF,SetA),pred,[],M1), | |
| 501 | create_texpr(member(CGH,SetB),pred,[],M2), | |
| 502 | conjunct_predicates([M1,M2],Pred). | |
| 503 | cleanup_pre(composition(Rel1,Rel2),set(couple(TD,TR)),I,comprehension_set([UIdD,UIdR],Pred),set(couple(TD,TR)),I,multi/rewrite_composition,[],[]) :- | |
| 504 | % change in Z3: lambda inside recursive functions was declared unsupported until proper support is provided (see https://github.com/Z3Prover/z3/issues/5813) | |
| 505 | % see mk_op_iteration_func_decl in /extensions/z3interface/src/cpp/main.cpp | |
| 506 | %translation_type(axiomatic), | |
| 507 | get_texpr_type(Rel1,set(couple(TD,TI))), | |
| 508 | unique_typed_id("_smt_tmp",TD,UIdD), | |
| 509 | unique_typed_id("_smt_tmp",TR,UIdR), | |
| 510 | unique_typed_id("_smt_tmp",TI,UIdI), | |
| 511 | create_texpr(couple(UIdD,UIdI),couple(TD,TI),[],CoupleDomToI), | |
| 512 | create_texpr(couple(UIdI,UIdR),couple(TI,TR),[],CoupleIToRan), | |
| 513 | create_texpr(member(CoupleDomToI,Rel1),pred,[],Member1), | |
| 514 | create_texpr(member(CoupleIToRan,Rel2),pred,[],Member2), | |
| 515 | conjunct_predicates([Member1,Member2],Inner), | |
| 516 | create_exists([UIdI],Inner,Pred). | |
| 517 | cleanup_pre(domain_restriction(Set,Rel),set(couple(TD,TR)),I,comprehension_set([UIdD,UIdR],Pred),set(couple(TD,TR)),I,multi/rewrite_domain_restriction,[],[]) :- | |
| 518 | translation_type(axiomatic), | |
| 519 | unique_typed_id("_smt_tmp",TD,UIdD), | |
| 520 | unique_typed_id("_smt_tmp",TR,UIdR), | |
| 521 | create_texpr(couple(UIdD,UIdR),couple(TD,TR),[],Couple), | |
| 522 | create_texpr(member(Couple,Rel),pred,[],MemberOfRel), | |
| 523 | create_texpr(member(UIdD,Set),pred,[],MemberOfSet), | |
| 524 | conjunct_predicates([MemberOfRel,MemberOfSet],Pred). | |
| 525 | cleanup_pre(domain_subtraction(Set,Rel),set(couple(TD,TR)),I,comprehension_set([UIdD,UIdR],Pred),set(couple(TD,TR)),I,multi/rewrite_domain_subtraction,[],[]) :- | |
| 526 | translation_type(axiomatic), | |
| 527 | unique_typed_id("_smt_tmp",TD,UIdD), | |
| 528 | unique_typed_id("_smt_tmp",TR,UIdR), | |
| 529 | create_texpr(couple(UIdD,UIdR),couple(TD,TR),[],Couple), | |
| 530 | create_texpr(member(Couple,Rel),pred,[],MemberOfRel), | |
| 531 | create_texpr(member(UIdD,Set),pred,[],MemberOfSet), | |
| 532 | create_negation(MemberOfSet,NotMemberOfSet), | |
| 533 | conjunct_predicates([MemberOfRel,NotMemberOfSet],Pred). | |
| 534 | cleanup_pre(range_restriction(Rel,Set),set(couple(TD,TR)),I,comprehension_set([UIdD,UIdR],Pred),set(couple(TD,TR)),I,multi/rewrite_range_restriction,[],[]) :- | |
| 535 | translation_type(axiomatic), | |
| 536 | unique_typed_id("_smt_tmp",TD,UIdD), | |
| 537 | unique_typed_id("_smt_tmp",TR,UIdR), | |
| 538 | create_texpr(couple(UIdD,UIdR),couple(TD,TR),[],Couple), | |
| 539 | create_texpr(member(Couple,Rel),pred,[],MemberOfRel), | |
| 540 | create_texpr(member(UIdR,Set),pred,[],MemberOfSet), | |
| 541 | conjunct_predicates([MemberOfRel,MemberOfSet],Pred). | |
| 542 | cleanup_pre(range_subtraction(Rel,Set),set(couple(TD,TR)),I,comprehension_set([UIdD,UIdR],Pred),set(couple(TD,TR)),I,multi/rewrite_range_subtraction,[],[]) :- | |
| 543 | translation_type(axiomatic), | |
| 544 | unique_typed_id("_smt_tmp",TD,UIdD), | |
| 545 | unique_typed_id("_smt_tmp",TR,UIdR), | |
| 546 | create_texpr(couple(UIdD,UIdR),couple(TD,TR),[],Couple), | |
| 547 | create_texpr(member(Couple,Rel),pred,[],MemberOfRel), | |
| 548 | create_texpr(member(UIdR,Set),pred,[],MemberOfSet), | |
| 549 | create_negation(MemberOfSet,NotMemberOfSet), | |
| 550 | conjunct_predicates([MemberOfRel,NotMemberOfSet],Pred). | |
| 551 | cleanup_pre(overwrite(Set1,Set2),set(couple(TD,TR)),I,union(Set2,DomSub),set(couple(TD,TR)),I,multi/rewrite_overwrite,[],[]) :- | |
| 552 | create_texpr(domain(Set2),set(TD),[],DomainSet2), | |
| 553 | create_texpr(domain_subtraction(DomainSet2,Set1),set(couple(TD,TR)),[],DomSub). | |
| 554 | cleanup_pre(reverse(Set),set(couple(TA,TB)),I,UnwrappedId,set(couple(TA,TB)),I,multi/reverse_to_forall,[AC],[UId]) :- | |
| 555 | translation_type(axiomatic), | |
| 556 | % the reverse is replaced by an identifier (uid) | |
| 557 | unique_typed_id("_smt_tmp",set(couple(TA,TB)),UId), | |
| 558 | get_texpr_expr(UId,UnwrappedId), | |
| 559 | % the identifer carries an additional constraint: | |
| 560 | % !(ida,idb).((ida,idb) : set <-> (idb,ida) : uid) | |
| 561 | unique_typed_id("_smt_tmp",TA,UIdA), | |
| 562 | unique_typed_id("_smt_tmp",TB,UIdB), | |
| 563 | create_texpr(couple(UIdA,UIdB),couple(TA,TB),[],CoupleAB), | |
| 564 | create_texpr(couple(UIdB,UIdA),couple(TB,TA),[],CoupleBA), | |
| 565 | ||
| 566 | create_texpr(member(CoupleAB,UId),pred,[],MemberA), | |
| 567 | create_texpr(member(CoupleBA,Set),pred,[],MemberB), | |
| 568 | create_implication(MemberA,MemberB,Direction1), | |
| 569 | create_implication(MemberB,MemberA,Direction2), | |
| 570 | % use two foralls instead of equivalence! | |
| 571 | create_forall([UIdA,UIdB],Direction1,AC1), | |
| 572 | create_forall([UIdA,UIdB],Direction2,AC2), | |
| 573 | conjunct_predicates([AC1,AC2],AC). | |
| 574 | cleanup_pre(cartesian_product(SetA,SetB),set(couple(TR,TD)),I,comprehension_set([UIdR,UIdD],Pred),set(couple(TR,TD)),I,multi/cartesian_product_to_set_comprehension,[],[]) :- | |
| 575 | translation_type(axiomatic), | |
| 576 | unique_typed_id("_smt_tmp",TD,UIdD), | |
| 577 | unique_typed_id("_smt_tmp",TR,UIdR), | |
| 578 | create_texpr(member(UIdR,SetA),pred,[],MemberOf1), | |
| 579 | create_texpr(member(UIdD,SetB),pred,[],MemberOf2), | |
| 580 | conjunct_predicates([MemberOf1,MemberOf2],Pred). | |
| 581 | cleanup_pre(Input,pred,I,C,pred,I2,multi/function_application_in_predicate_position_1,[],[]) :- | |
| 582 | Input =.. [Pred,E,Arg], | |
| 583 | \+ is_list(E), % avoids quantifiers | |
| 584 | is_texpr(E), is_texpr(Fun), | |
| 585 | get_texpr_expr(E,function(Fun,Elem)), | |
| 586 | get_texpr_type(Fun,set(couple(RanT,DomT))), | |
| 587 | unique_typed_id("_smt_tmp",DomT,UId), | |
| 588 | create_texpr(couple(Elem,UId),couple(RanT,DomT),[],Couple), | |
| 589 | create_texpr(member(Couple,Fun),pred,[],CoupleInFun), | |
| 590 | Output =.. [Pred,UId,Arg], | |
| 591 | create_texpr(Output,pred,I,UIdInS), | |
| 592 | conjunct_predicates([CoupleInFun,UIdInS],Inner), | |
| 593 | create_exists([UId],Inner,b(C,pred,I2)). | |
| 594 | cleanup_pre(Input,pred,I,C,pred,I2,multi/function_application_in_predicate_position_2,[],[]) :- | |
| 595 | Input =.. [Pred,E,Arg], | |
| 596 | \+ is_list(Arg), % avoids quantifiers | |
| 597 | is_texpr(Arg), is_texpr(Fun), | |
| 598 | get_texpr_expr(Arg,function(Fun,Elem)), | |
| 599 | get_texpr_type(Fun,set(couple(RanT,DomT))), | |
| 600 | unique_typed_id("_smt_tmp",DomT,UId), | |
| 601 | create_texpr(couple(Elem,UId),couple(RanT,DomT),[],Couple), | |
| 602 | create_texpr(member(Couple,Fun),pred,[],CoupleInFun), | |
| 603 | Output =.. [Pred,E,UId], | |
| 604 | create_texpr(Output,pred,I,UIdInS), | |
| 605 | conjunct_predicates([CoupleInFun,UIdInS],Inner), | |
| 606 | create_exists([UId],Inner,b(C,pred,I2)). | |
| 607 | /*cleanup_pre(Expr,Type,I,NExpr,Type,I,multi/precompute_values,[],[]) :- | |
| 608 | precompute_values_e(Expr, TNExpr), | |
| 609 | Expr \= TNExpr, | |
| 610 | !, | |
| 611 | NExpr = TNExpr.*/ | |
| 612 | % in case the former two rules have not removed a function/2 | |
| 613 | cleanup_pre(function(F,X),Type,I,UnwrappedId,Type,I,multi/function_application_to_membership,[AC],[UId]) :- | |
| 614 | unique_typed_id("_smt_tmp",Type,UId), | |
| 615 | get_texpr_expr(UId,UnwrappedId), | |
| 616 | get_texpr_type(F,set(FunType)), | |
| 617 | create_texpr(couple(X,UId),FunType,[],CoupleInFunction), | |
| 618 | create_texpr(member(CoupleInFunction,F),pred,[],AC). | |
| 619 | ||
| 620 | % ---------------------------------------------------------------------------- | |
| 621 | % the following rules introduce new identifiers and quantifiers to define them | |
| 622 | % thus, they should be the last rules executed and be avoided if possible | |
| 623 | % some of the expressions that are rewritten here can be removed if they | |
| 624 | % occur in another context, i.e. f(x) in the predicate f(x) : S | |
| 625 | % see rules above | |
| 626 | % ---------------------------------------------------------------------------- | |
| 627 | cleanup_pre(integer_set('INTEGER'),set(integer),I,UnwrappedId,set(integer),I,multi/rewrite_integer_set_if_above_fails,[AC],[UId]) :- | |
| 628 | % the integer set is replaced by an identifier (uid) | |
| 629 | unique_typed_id("_smt_tmp",set(integer),UId), | |
| 630 | get_texpr_expr(UId,UnwrappedId), | |
| 631 | ||
| 632 | % the identifer carries an additional constraint: | |
| 633 | % !(id).(id : uid) | |
| 634 | unique_typed_id("_smt_tmp",integer,IdToQuantify), | |
| 635 | ||
| 636 | create_texpr(member(IdToQuantify,UId),pred,[],MemberIn), | |
| 637 | ||
| 638 | create_forall([IdToQuantify],MemberIn,AC). | |
| 639 | cleanup_pre(min_real(Set),real,I,UnwrappedId,real,I,multi/min_real_to_definition,Args,Ids) :- | |
| 640 | cleanup_pre(min(Set),real,I,UnwrappedId,real,I,_,Args,Ids). | |
| 641 | cleanup_pre(max_real(Set),real,I,UnwrappedId,real,I,multi/max_real_to_definition,Args,Ids) :- | |
| 642 | cleanup_pre(max(Set),real,I,UnwrappedId,real,I,_,Args,Ids). | |
| 643 | cleanup_pre(min(Set),IntOrReal,I,UnwrappedId,IntOrReal,I,multi/min_to_definition,[AC1,AC2],[UId]) :- | |
| 644 | (IntOrReal == integer; IntOrReal == real), | |
| 645 | unique_typed_id("_smt_tmp",IntOrReal,UId), | |
| 646 | get_texpr_expr(UId,UnwrappedId), | |
| 647 | % two axioms: | |
| 648 | % !(x).(x : Set => uid <= x) | |
| 649 | % #(x).(x : Set & uid = x) | |
| 650 | ||
| 651 | unique_typed_id("_smt_tmp",IntOrReal,QuantifiedVar), | |
| 652 | ||
| 653 | create_texpr(less_equal(UId,QuantifiedVar),pred,[],LessEqual), | |
| 654 | create_texpr(equal(UId,QuantifiedVar),pred,[],Equal), | |
| 655 | create_texpr(member(QuantifiedVar,Set),pred,[],QuantifiedInSet), | |
| 656 | ||
| 657 | conjunct_predicates([QuantifiedInSet,Equal],ExistsInner), | |
| 658 | create_implication(QuantifiedInSet,LessEqual,ForallInner), | |
| 659 | ||
| 660 | create_exists([QuantifiedVar],ExistsInner,AC1), | |
| 661 | ||
| 662 | create_forall([QuantifiedVar],ForallInner,AC2). | |
| 663 | cleanup_pre(max(Set),IntOrReal,I,UnwrappedId,IntOrReal,I,multi/max_to_definition,[AC1,AC2],[UId]) :- | |
| 664 | (IntOrReal == integer; IntOrReal == real), | |
| 665 | unique_typed_id("_smt_tmp",IntOrReal,UId), | |
| 666 | get_texpr_expr(UId,UnwrappedId), | |
| 667 | % two axioms: | |
| 668 | % !(x).(x : Set => uid >= x) | |
| 669 | % #(x).(x : Set & uid = x) | |
| 670 | ||
| 671 | unique_typed_id("_smt_tmp",IntOrReal,QuantifiedVar), | |
| 672 | ||
| 673 | create_texpr(greater_equal(UId,QuantifiedVar),pred,[],GreaterEqual), | |
| 674 | create_texpr(equal(UId,QuantifiedVar),pred,[],Equal), | |
| 675 | create_texpr(member(QuantifiedVar,Set),pred,[],QuantifiedInSet), | |
| 676 | ||
| 677 | conjunct_predicates([QuantifiedInSet,Equal],ExistsInner), | |
| 678 | create_implication(QuantifiedInSet,GreaterEqual,ForallInner), | |
| 679 | ||
| 680 | create_exists([QuantifiedVar],ExistsInner,AC1), | |
| 681 | ||
| 682 | create_forall([QuantifiedVar],ForallInner,AC2). | |
| 683 | cleanup_pre(card(Set),integer,I,UnwrappedId,integer,I,multi/card_to_exists,[AC1,AC2],[UId]) :- | |
| 684 | unique_typed_id("_smt_tmp",integer,UId), | |
| 685 | get_texpr_expr(UId,UnwrappedId), | |
| 686 | get_texpr_type(Set,set(SetT)), | |
| 687 | unique_typed_id("_smt_tmp",set(couple(integer,SetT)),ForExists), | |
| 688 | create_texpr(interval(b(integer(1),integer,[]),UId),set(integer),[],Interval), | |
| 689 | create_texpr(total_bijection(Interval,Set),set(set(couple(integer,SetT))),[],Bijection), | |
| 690 | create_texpr(member(ForExists,Bijection),pred,[],MemberOf), | |
| 691 | create_exists([ForExists],MemberOf,AC1), | |
| 692 | % without the following constraint, the empty set could have any (negative) cardinality | |
| 693 | create_texpr(greater_equal(UId,b(integer(0),integer,[])),pred,[],AC2). | |
| 694 | cleanup_pre(finite(Set),pred,I,ExistsExpr,pred,I,multi/finite_to_forall,[],[]) :- | |
| 695 | % #(b,f).(b:NATURAL & f: Set --> 0..b) | |
| 696 | get_texpr_type(Set,set(ST)), | |
| 697 | unique_typed_id("_smt_tmp",integer,IDB), | |
| 698 | create_texpr(interval(b(integer(0),integer,[]),IDB),set(integer),[],Interval0ToB), | |
| 699 | unique_typed_id("_smt_tmp",set(couple(ST,integer)),IDFun), | |
| 700 | create_texpr(total_injection(Set,Interval0ToB),set(set(couple(ST,integer))),[],Functions), | |
| 701 | create_texpr(member(IDFun,Functions),pred,[],Member), | |
| 702 | create_exists([IDB,IDFun],Member,Exists), | |
| 703 | get_texpr_expr(Exists,ExistsExpr). | |
| 704 | cleanup_pre(comprehension_set(Identifiers,Pred),set(X),I,UnwrappedId,set(X),I,multi/comprehension_set_to_forall,[AC],[UId]) :- | |
| 705 | % NOTE: currently the comprehension sets generated are not valid according to B typing rules | |
| 706 | % expr_list_to_couple_expr corrects this | |
| 707 | %( | |
| 708 | translation_type(axiomatic), | |
| 709 | %; translation_type(constructive), % we use Z3's lambda for constructive translation | |
| 710 | % \+ (member(b(_,_,LambdaIdInfo), Identifiers), member(lambda_result(_), LambdaIdInfo)) | |
| 711 | %), | |
| 712 | %print(X),nl, print(Identifiers),nl, | |
| 713 | ( expr_list_to_couple_expr(Identifiers,X,IDCouple) | |
| 714 | -> true | |
| 715 | ; add_message(cleanup_pre, 'Could not transform comprehension_set into quantifiers:~n ', b(comprehension_set(Identifiers,Pred),set(X),I)) | |
| 716 | ), | |
| 717 | % the set comprehension is replaced by an identifier (uid) | |
| 718 | unique_typed_id("_smt_tmp",set(X),UId), | |
| 719 | get_texpr_expr(UId,UnwrappedId), | |
| 720 | % the identifer carries an additional constraint: | |
| 721 | % !(id).(Pred(id) <-> id : uid) | |
| 722 | create_texpr(member(IDCouple,UId),pred,[],MemberInComprehension), | |
| 723 | create_implication(Pred,MemberInComprehension,Direction1), | |
| 724 | create_implication(MemberInComprehension,Pred,Direction2), | |
| 725 | % use two foralls instead of equivalence! | |
| 726 | ||
| 727 | create_forall(Identifiers,Direction1,AC1), | |
| 728 | create_forall(Identifiers,Direction2,AC2), | |
| 729 | conjunct_predicates([AC1,AC2],AC). | |
| 730 | /* doesn't seem to be correct, see :z3-double-check rx:BOOL <-> BOOL & not(( id(BOOL) ; rx) = rx) | |
| 731 | cleanup_pre(identity(Set),set(couple(SetT,SetT)),I,UnwrappedId,set(couple(SetT,SetT)),I,multi/identity_to_forall,[AC],[UId]) :- | |
| 732 | translation_type(axiomatic), | |
| 733 | % the identity is replaced by an identifier (uid) | |
| 734 | unique_typed_id("_smt_tmp",set(couple(SetT,SetT)),UId), | |
| 735 | get_texpr_expr(UId,UnwrappedId), | |
| 736 | % the identifer carries an additional constraint: | |
| 737 | % !(id).(id : set <-> (id,id) : uid) | |
| 738 | unique_typed_id("_smt_tmp",SetT,UIdInSet), | |
| 739 | create_texpr(couple(UIdInSet,UIdInSet),couple(SetT,SetT),[],IdCouple), | |
| 740 | create_texpr(member(UIdInSet,Set),pred,[],MemberInSet), | |
| 741 | create_texpr(member(IdCouple,UId),pred,[],MemberInIdentity), | |
| 742 | create_implication(MemberInIdentity,MemberInSet,Direction1), | |
| 743 | create_implication(MemberInSet,MemberInIdentity,Direction2), | |
| 744 | % use two foralls instead of equivalence! | |
| 745 | ||
| 746 | create_forall([UIdInSet],Direction1,AC1), | |
| 747 | create_forall([UIdInSet],Direction2,AC2), | |
| 748 | conjunct_predicates([AC1,AC2],AC).*/ | |
| 749 | cleanup_pre(domain(Set),set(TD),I,UnwrappedId,set(TD),I,multi/domain_to_forall,[AC],[UId]) :- | |
| 750 | translation_type(axiomatic), | |
| 751 | % the alternative translation of domain and range using lambda is not supported by the incremental solver | |
| 752 | % because an existential quantification is used in the body of the lambda ("internalization of exists is not supported") | |
| 753 | % we thus rewrite these operators here if the incremental solver is used, otherwise they are translated in z3interface/../main.cpp | |
| 754 | % the domain is replaced by an identifier (uid) | |
| 755 | get_texpr_type(Set,set(couple(TD,TR))), | |
| 756 | unique_typed_id("_smt_tmp",set(TD),UId), | |
| 757 | get_texpr_expr(UId,UnwrappedId), | |
| 758 | % the identifer carries an additional constraint: | |
| 759 | % !(id).(id : uid <-> #(idr) : (id,idr) : set) | |
| 760 | unique_typed_id("_smt_tmp",TD,UIdInDomain), | |
| 761 | unique_typed_id("_smt_tmp",TR,UIdInRange), | |
| 762 | ||
| 763 | create_texpr(couple(UIdInDomain,UIdInRange),couple(TD,TR),[],CoupleDR), | |
| 764 | create_texpr(member(CoupleDR,Set),pred,[],CoupleInSet), | |
| 765 | create_exists([UIdInRange],CoupleInSet,ExistsRanElement), | |
| 766 | ||
| 767 | create_texpr(member(UIdInDomain,UId),pred,[],MemberInDomain), | |
| 768 | ||
| 769 | create_implication(ExistsRanElement,MemberInDomain,Direction1), | |
| 770 | create_implication(MemberInDomain,ExistsRanElement,Direction2), | |
| 771 | % use two foralls instead of equivalence! | |
| 772 | ||
| 773 | create_forall([UIdInDomain],Direction1,AC1), | |
| 774 | create_forall([UIdInDomain],Direction2,AC2), | |
| 775 | conjunct_predicates([AC1,AC2],AC). | |
| 776 | cleanup_pre(range(Set),set(TR),I,UnwrappedId,set(TR),I,multi/range_to_forall,[AC],[UId]) :- | |
| 777 | (member(no_lambda_translation, I); translation_type(axiomatic)), | |
| 778 | % the range is replaced by an identifier (uid) | |
| 779 | get_texpr_type(Set,set(couple(TD,TR))), | |
| 780 | unique_typed_id("_smt_tmp",set(TR),UId), | |
| 781 | get_texpr_expr(UId,UnwrappedId), | |
| 782 | % the identifer carries an additional constraint: | |
| 783 | % !(id).(id : uid <-> #(idd) : (idd,id) : set) | |
| 784 | unique_typed_id("_smt_tmp",TD,UIdInDomain), | |
| 785 | unique_typed_id("_smt_tmp",TR,UIdInRange), | |
| 786 | ||
| 787 | create_texpr(couple(UIdInDomain,UIdInRange),couple(TD,TR),[],CoupleDR), | |
| 788 | create_texpr(member(CoupleDR,Set),pred,[],CoupleInSet), | |
| 789 | create_exists([UIdInDomain],CoupleInSet,ExistsDomElement), | |
| 790 | ||
| 791 | create_texpr(member(UIdInRange,UId),pred,[],MemberInRange), | |
| 792 | create_implication(ExistsDomElement,MemberInRange,Direction1), | |
| 793 | create_implication(MemberInRange,ExistsDomElement,Direction2), | |
| 794 | % use two foralls instead of equivalence! | |
| 795 | ||
| 796 | create_forall([UIdInRange],Direction1,AC1), | |
| 797 | create_forall([UIdInRange],Direction2,AC2), | |
| 798 | conjunct_predicates([AC1,AC2],AC). | |
| 799 | cleanup_pre(image(Function,Set),set(TR),I,UnwrappedId,set(TR),I,multi/image_to_forall,[AC],[UId]) :- | |
| 800 | translation_type(axiomatic), | |
| 801 | % the image is replaced by an identifier (uid) | |
| 802 | get_texpr_type(Function,set(couple(TD,TR))), | |
| 803 | unique_typed_id("_smt_tmp",set(TR),UId), | |
| 804 | get_texpr_expr(UId,UnwrappedId), | |
| 805 | % the identifer carries an additional constraint: | |
| 806 | % !(idr).(idr : uid <-> #(idd) : idd:set & (idd,idr) : function) | |
| 807 | unique_typed_id("_smt_tmp",TD,UIdInDomain), | |
| 808 | unique_typed_id("_smt_tmp",TR,UIdInRange), | |
| 809 | ||
| 810 | create_texpr(couple(UIdInDomain,UIdInRange),couple(TD,TR),[],CoupleDR), | |
| 811 | create_texpr(member(CoupleDR,Function),pred,[],CoupleInFunction), | |
| 812 | create_texpr(member(UIdInDomain,Set),pred,[],DomElementInSet), | |
| 813 | conjunct_predicates([CoupleInFunction,DomElementInSet],ExistsInner), | |
| 814 | create_exists([UIdInDomain],ExistsInner,RHS), | |
| 815 | ||
| 816 | create_texpr(member(UIdInRange,UId),pred,[],LHS), | |
| 817 | ||
| 818 | create_implication(LHS,RHS,Direction1), | |
| 819 | create_implication(RHS,LHS,Direction2), | |
| 820 | % use two foralls instead of equivalence! | |
| 821 | ||
| 822 | create_forall([UIdInRange],Direction1,AC1), | |
| 823 | create_forall([UIdInRange],Direction2,AC2), | |
| 824 | conjunct_predicates([AC1,AC2],AC). | |
| 825 | cleanup_pre(external_pred_call('LEQ_SYM',_),pred,I,truth,pred,I,multi/remove_leq_sym,[],[]) :- | |
| 826 | debug_println(19,'Ignoring LEQ_SYM predicate'). | |
| 827 | ||
| 828 | cleanup_post_with_path(OExpr,OType,OInfo,NExpr,NType,NInfo,Mode/Rule,_Path,[],[]) :- | |
| 829 | cleanup_post(OExpr,OType,OInfo,NExpr,NType,NInfo,Mode/Rule). | |
| 830 | % remove membership / subset if only used for typing | |
| 831 | cleanup_post(subset(A,B),pred,I,truth,pred,[was(subset(A,B))|I],multi/remove_type_subset) :- | |
| 832 | is_just_type(B), !. | |
| 833 | cleanup_post(member(X,B),pred,I,truth,pred,[was(member(X,B))|I],multi/remove_type_member) :- | |
| 834 | is_just_type(B), !. | |
| 835 | cleanup_post(not_member(X,B),pred,I,falsity,pred,[was(not_member(X,B))|I],multi/remove_type_not_member) :- | |
| 836 | is_just_type(B), !. | |
| 837 | ||
| 838 | % using create_couple would be much easier: | |
| 839 | %expr_list_to_couple_expr(Exprs,TypeOfCoupleExpr,Result) :- !, bsyntaxtree:create_couple(Exprs,Result). | |
| 840 | % but we seem to need this more complex version due to the fact that some translation rules | |
| 841 | % like for parallel or direct_product generate incorrect comprehension sets | |
| 842 | expr_list_to_couple_expr(Exprs,TypeOfCoupleExpr,Result) :- | |
| 843 | expr_list_to_couple_expr(Exprs,TypeOfCoupleExpr,[],Result). | |
| 844 | expr_list_to_couple_expr([T],_Type,[],R) :- !, T=R. | |
| 845 | expr_list_to_couple_expr([E|Es],couple(TA,TR),Rest,R) :- | |
| 846 | get_texpr_type(E,TA),!, % type is matching | |
| 847 | expr_list_to_couple_expr(Es,TR,Rest,RHS), | |
| 848 | get_texpr_type(RHS,RHST), get_texpr_type(E,ET), | |
| 849 | create_texpr(couple(E,RHS),couple(ET,RHST),[],R). | |
| 850 | expr_list_to_couple_expr(Es,couple(TA,TR),Rest,R) :- | |
| 851 | TA = couple(SA,SB), | |
| 852 | expr_list_to_couple_expr(Es,SA,TRest,LHS), | |
| 853 | !, | |
| 854 | expr_list_to_couple_expr(TRest,SB,TRest2,RHS), | |
| 855 | get_texpr_type(RHS,RHST), get_texpr_type(LHS,LHST), | |
| 856 | create_texpr(couple(LHS,RHS),couple(LHST,RHST),[],R1), | |
| 857 | expr_list_to_couple_expr(TRest2,TR,Rest,R2), | |
| 858 | !, | |
| 859 | get_texpr_type(R1,R1T), get_texpr_type(R2,R2T), | |
| 860 | create_texpr(couple(R1,R2),couple(R1T,R2T),[],R). | |
| 861 | expr_list_to_couple_expr([T|Ts],_Type,Ts,R) :- !, T=R. | |
| 862 | ||
| 863 | is_interval(BT,Low,Up) :- | |
| 864 | get_texpr_expr(BT,B), | |
| 865 | ( B = interval(Low,Up) -> true | |
| 866 | ; B = value(Val), nonvar(Val), | |
| 867 | is_interval_closure(Val,L,U) -> | |
| 868 | Low = b(integer(L),integer,[]), | |
| 869 | Up = b(integer(U),integer,[])). | |
| 870 | ||
| 871 | ||
| 872 | rewrite_subset_of_integer_set(Sub,Super,COut) :- | |
| 873 | unique_typed_id("_smt_tmp",integer,ForAllVar), | |
| 874 | create_texpr(member(ForAllVar,Sub),pred,[],LHS), | |
| 875 | create_texpr(member(ForAllVar,Super),pred,[],RHS), % will be replaced by another rule | |
| 876 | create_implication(LHS,RHS,Inner), | |
| 877 | create_forall([ForAllVar],Inner,C), | |
| 878 | get_texpr_expr(C,COut). | |
| 879 | ||
| 880 | rewrite_struct_ids(Record,field(Id,TPowerset),Constraint) :- | |
| 881 | % b_compile/6 might have transformed ASTs to values | |
| 882 | TPowerset \= b(_,_,_), | |
| 883 | !, | |
| 884 | get_texpr_type(Record,record([field(_,IdType)|_])), | |
| 885 | Powerset = b(value(TPowerset),set(IdType),[]), | |
| 886 | create_texpr(record_field(Record,Id),IdType,[],TheField), | |
| 887 | create_texpr(member(TheField,Powerset),pred,[],Constraint). | |
| 888 | rewrite_struct_ids(Record,field(Id,Powerset),Constraint) :- | |
| 889 | get_texpr_type(Powerset,set(IdType)), | |
| 890 | create_texpr(record_field(Record,Id),IdType,[],TheField), | |
| 891 | create_texpr(member(TheField,Powerset),pred,[],Constraint). | |
| 892 | ||
| 893 | % relations | |
| 894 | rewrite_member_of_function(ID,Function,TypeConstraintOut) :- | |
| 895 | get_texpr_expr(Function,relations(Dom,Ran)), | |
| 896 | get_texpr_type(Function,set(set(couple(DomT,RanT)))), | |
| 897 | % relations: only typing constraint !(x,y).((x,y) : ID => x : Dom & y : Ran) | |
| 898 | unique_typed_id("_smt_tmp",DomT,UIdDom), | |
| 899 | unique_typed_id("_smt_tmp",RanT,UIdRan), | |
| 900 | create_texpr(couple(UIdDom,UIdRan),couple(DomT,RanT),[],UIdCouple), | |
| 901 | create_texpr(member(UIdCouple,ID),pred,[],LHS), | |
| 902 | create_texpr(member(UIdDom,Dom),pred,[],RHS1), | |
| 903 | create_texpr(member(UIdRan,Ran),pred,[],RHS2), | |
| 904 | conjunct_predicates([RHS1,RHS2],RHS), | |
| 905 | create_implication(LHS,RHS,TypeConsInner), | |
| 906 | ||
| 907 | create_forall([UIdDom,UIdRan],TypeConsInner,TypeConstraint), | |
| 908 | get_texpr_expr(TypeConstraint,TypeConstraintOut). | |
| 909 | rewrite_member_of_function(ID,Function,ConstraintOut) :- | |
| 910 | get_texpr_expr(Function,total_relation(Dom,Ran)), | |
| 911 | get_texpr_type(Function,set(set(couple(DomT,RanT)))), | |
| 912 | % total_relation: relation & !(x).(x : Dom => #(y).(y : Ran & (x,y):Id)) | |
| 913 | unique_typed_id("_smt_tmp",DomT,UIdDom), | |
| 914 | unique_typed_id("_smt_tmp",RanT,UIdRan), | |
| 915 | create_texpr(couple(UIdDom,UIdRan),couple(DomT,RanT),[],UIdCouple), | |
| 916 | create_texpr(member(UIdCouple,ID),pred,[],CoupleInID), | |
| 917 | create_exists([UIdRan],CoupleInID,RHS), | |
| 918 | create_texpr(member(UIdDom,Dom),pred,[],LHS), | |
| 919 | create_implication(LHS,RHS,FunConsInner), | |
| 920 | create_forall([UIdDom],FunConsInner,FunConstraint), | |
| 921 | create_texpr(relations(Dom,Ran),set(set(couple(DomT,RanT))),[],Relations), | |
| 922 | create_texpr(member(ID,Relations),pred,[],IsRelation), | |
| 923 | ConstraintOut = conjunct(IsRelation,FunConstraint). | |
| 924 | rewrite_member_of_function(ID,Function,ConstraintOut) :- | |
| 925 | get_texpr_expr(Function,surjection_relation(Dom,Ran)), | |
| 926 | get_texpr_type(Function,set(set(couple(DomT,RanT)))), | |
| 927 | % surjection_relation: relation & ran = T | |
| 928 | create_texpr(range(ID),set(RanT),[],Range), | |
| 929 | create_texpr(equal(Range,Ran),pred,[],FunConstraint), | |
| 930 | create_texpr(relations(Dom,Ran),set(set(couple(DomT,RanT))),[],Relations), | |
| 931 | create_texpr(member(ID,Relations),pred,[],IsRelation), | |
| 932 | ConstraintOut = conjunct(IsRelation,FunConstraint). | |
| 933 | rewrite_member_of_function(ID,Function,ConstraintOut) :- | |
| 934 | get_texpr_expr(Function,total_surjection_relation(Dom,Ran)), | |
| 935 | get_texpr_type(Function,set(set(couple(DomT,RanT)))), | |
| 936 | % total_surjection_relation: total_relation & surjection_relation | |
| 937 | create_texpr(total_relation(Dom,Ran),set(set(couple(DomT,RanT))),[],TotalRelations), | |
| 938 | create_texpr(member(ID,TotalRelations),pred,[],IsTotalRelation), | |
| 939 | create_texpr(surjection_relation(Dom,Ran),set(set(couple(DomT,RanT))),[],SurjectionRelations), | |
| 940 | create_texpr(member(ID,SurjectionRelations),pred,[],IsSurjectionRelation), | |
| 941 | ConstraintOut = conjunct(IsTotalRelation,IsSurjectionRelation). | |
| 942 | % functions | |
| 943 | rewrite_member_of_function(ID,Function,ConstraintOut) :- | |
| 944 | get_texpr_expr(Function,partial_function(Dom,Ran)), | |
| 945 | get_texpr_type(Function,set(set(couple(DomT,RanT)))), | |
| 946 | % partial_function: relation & !(x,y,z).((x,y) : ID & (x,z) : ID => y = z) | |
| 947 | unique_typed_id("_smt_tmp",DomT,UIdDom), | |
| 948 | unique_typed_id("_smt_tmp",RanT,UIdRan), | |
| 949 | unique_typed_id("_smt_tmp",RanT,UIdRan2), | |
| 950 | create_texpr(couple(UIdDom,UIdRan),couple(DomT,RanT),[],UIdCouple), | |
| 951 | create_texpr(couple(UIdDom,UIdRan2),couple(DomT,RanT),[],UIdCouple2), | |
| 952 | create_texpr(member(UIdCouple,ID),pred,[],C1InID), | |
| 953 | create_texpr(member(UIdCouple2,ID),pred,[],C2InID), | |
| 954 | create_texpr(equal(UIdRan,UIdRan2),pred,[],RHS), | |
| 955 | conjunct_predicates([C1InID,C2InID],LHS), | |
| 956 | create_implication(LHS,RHS,FunConsInner), | |
| 957 | ||
| 958 | create_forall([UIdDom,UIdRan,UIdRan2],FunConsInner,FunConstraint), | |
| 959 | % add typing: is a relation | |
| 960 | create_texpr(relations(Dom,Ran),set(set(couple(DomT,RanT))),[],Relations), | |
| 961 | create_texpr(member(ID,Relations),pred,[],IsRelation), | |
| 962 | ConstraintOut = conjunct(IsRelation,FunConstraint). | |
| 963 | rewrite_member_of_function(ID,Function,ConstraintOut) :- | |
| 964 | get_texpr_expr(Function,total_function(Dom,Ran)), | |
| 965 | get_texpr_type(Function,set(set(couple(DomT,RanT)))), | |
| 966 | % total_function: partial_function & !(x).(x : Dom => #(y).(y : Ran & (x,y):Id)) | |
| 967 | unique_typed_id("_smt_tmp",DomT,UIdDom), | |
| 968 | unique_typed_id("_smt_tmp",RanT,UIdRan), | |
| 969 | create_texpr(couple(UIdDom,UIdRan),couple(DomT,RanT),[],UIdCouple), | |
| 970 | create_texpr(member(UIdCouple,ID),pred,[],CoupleInID), | |
| 971 | create_exists([UIdRan],CoupleInID,RHS), | |
| 972 | create_texpr(member(UIdDom,Dom),pred,[],LHS), | |
| 973 | create_implication(LHS,RHS,FunConsInner), | |
| 974 | create_forall([UIdDom],FunConsInner,FunConstraint), | |
| 975 | % add typing: is a partial_function | |
| 976 | create_texpr(partial_function(Dom,Ran),set(set(couple(DomT,RanT))),[],PFunctions), | |
| 977 | create_texpr(member(ID,PFunctions),pred,[],IsPFunction), | |
| 978 | ConstraintOut = conjunct(IsPFunction,FunConstraint). | |
| 979 | % injections | |
| 980 | rewrite_member_of_function(ID,Function,ConstraintOut) :- | |
| 981 | get_texpr_expr(Function,partial_injection(Dom,Ran)), | |
| 982 | get_texpr_type(Function,set(set(couple(DomT,RanT)))), | |
| 983 | % partial_injection: partial_function & !(x1,x2,y).((x1,y) : ID & (x2,y) : ID => x1 = x2) | |
| 984 | unique_typed_id("_smt_tmp",DomT,UIdDom1), | |
| 985 | unique_typed_id("_smt_tmp",DomT,UIdDom2), | |
| 986 | unique_typed_id("_smt_tmp",RanT,UIdRan), | |
| 987 | create_texpr(couple(UIdDom1,UIdRan),couple(DomT,RanT),[],UIdCouple), | |
| 988 | create_texpr(couple(UIdDom2,UIdRan),couple(DomT,RanT),[],UIdCouple2), | |
| 989 | create_texpr(member(UIdCouple,ID),pred,[],C1InID), | |
| 990 | create_texpr(member(UIdCouple2,ID),pred,[],C2InID), | |
| 991 | create_texpr(equal(UIdDom1,UIdDom2),pred,[],RHS), | |
| 992 | conjunct_predicates([C1InID,C2InID],LHS), | |
| 993 | create_implication(LHS,RHS,FunConsInner), | |
| 994 | ||
| 995 | create_forall([UIdDom1,UIdDom2,UIdRan],FunConsInner,FunConstraint), | |
| 996 | % add typing: is a partial_function | |
| 997 | create_texpr(partial_function(Dom,Ran),set(set(couple(DomT,RanT))),[],PartialFunctions), | |
| 998 | create_texpr(member(ID,PartialFunctions),pred,[],IsPartialFunction), | |
| 999 | ConstraintOut = conjunct(IsPartialFunction,FunConstraint). | |
| 1000 | rewrite_member_of_function(ID,Function,ConstraintOut) :- | |
| 1001 | get_texpr_expr(Function,total_injection(Dom,Ran)), | |
| 1002 | get_texpr_type(Function,set(set(couple(DomT,RanT)))), | |
| 1003 | % total_injection: total_function & partial_injection | |
| 1004 | create_texpr(total_function(Dom,Ran),set(set(couple(DomT,RanT))),[],TotalFunctions), | |
| 1005 | create_texpr(member(ID,TotalFunctions),pred,[],IsTotalFunction), | |
| 1006 | create_texpr(partial_injection(Dom,Ran),set(set(couple(DomT,RanT))),[],PartialInjections), | |
| 1007 | create_texpr(member(ID,PartialInjections),pred,[],IsPartialInjection), | |
| 1008 | ConstraintOut = conjunct(IsTotalFunction,IsPartialInjection). | |
| 1009 | % surjections | |
| 1010 | rewrite_member_of_function(ID,Function,ConstraintOut) :- | |
| 1011 | get_texpr_expr(Function,partial_surjection(Dom,Ran)), | |
| 1012 | get_texpr_type(Function,set(set(couple(DomT,RanT)))), | |
| 1013 | % partial_surjection: partial_function & ran = T | |
| 1014 | create_texpr(range(ID),set(RanT),[],TRange), | |
| 1015 | % TO DO: there is a bug when translating this range as a lambda function, happens for card, possible bug in Z3 | |
| 1016 | add_texpr_infos(TRange, [no_lambda_translation], Range), | |
| 1017 | create_texpr(equal(Range,Ran),pred,[],FunConstraint), | |
| 1018 | % add typing: is a partial_function | |
| 1019 | create_texpr(partial_function(Dom,Ran),set(set(couple(DomT,RanT))),[],PFunctions), | |
| 1020 | create_texpr(member(ID,PFunctions),pred,[],IsPFunction), | |
| 1021 | ConstraintOut = conjunct(IsPFunction,FunConstraint). | |
| 1022 | rewrite_member_of_function(ID,Function,ConstraintOut) :- | |
| 1023 | get_texpr_expr(Function,total_surjection(Dom,Ran)), | |
| 1024 | get_texpr_type(Function,set(set(couple(DomT,RanT)))), | |
| 1025 | % total_surjection: total_function & partial_surjection | |
| 1026 | create_texpr(total_function(Dom,Ran),set(set(couple(DomT,RanT))),[],TotalFunctions), | |
| 1027 | create_texpr(member(ID,TotalFunctions),pred,[],IsTotalFunction), | |
| 1028 | create_texpr(partial_surjection(Dom,Ran),set(set(couple(DomT,RanT))),[],PartialSurjections), | |
| 1029 | create_texpr(member(ID,PartialSurjections),pred,[],IsPartialSurjection), | |
| 1030 | ConstraintOut = conjunct(IsTotalFunction,IsPartialSurjection). | |
| 1031 | % bijections | |
| 1032 | rewrite_member_of_function(ID,Function,ConstraintOut) :- | |
| 1033 | get_texpr_expr(Function,partial_bijection(Dom,Ran)), | |
| 1034 | get_texpr_type(Function,set(set(couple(DomT,RanT)))), | |
| 1035 | % partial_bijection: partial_surjection & partial_injection | |
| 1036 | create_texpr(partial_surjection(Dom,Ran),set(set(couple(DomT,RanT))),[],PartialSurjections), | |
| 1037 | create_texpr(member(ID,PartialSurjections),pred,[],IsPartialSurjection), | |
| 1038 | create_texpr(partial_injection(Dom,Ran),set(set(couple(DomT,RanT))),[],PartialInjections), | |
| 1039 | create_texpr(member(ID,PartialInjections),pred,[],IsPartialInjection), | |
| 1040 | ConstraintOut = conjunct(IsPartialSurjection,IsPartialInjection). | |
| 1041 | rewrite_member_of_function(ID,Function,ConstraintOut) :- | |
| 1042 | get_texpr_expr(Function,total_bijection(Dom,Ran)), | |
| 1043 | get_texpr_type(Function,set(set(couple(DomT,RanT)))), | |
| 1044 | % total_bijection: total_surjection & total_injection | |
| 1045 | create_texpr(total_surjection(Dom,Ran),set(set(couple(DomT,RanT))),[],TotalSurjections), | |
| 1046 | create_texpr(member(ID,TotalSurjections),pred,[],IsTotalSurjection), | |
| 1047 | create_texpr(total_injection(Dom,Ran),set(set(couple(DomT,RanT))),[],TotalInjections), | |
| 1048 | create_texpr(member(ID,TotalInjections),pred,[],IsTotalInjection), | |
| 1049 | ConstraintOut = conjunct(IsTotalSurjection,IsTotalInjection). | |
| 1050 | ||
| 1051 | rewrite_equal_to_ge_le(ID,GlobalSet,Constraint) :- | |
| 1052 | unique_typed_id("_smt_tmp",integer,UId), | |
| 1053 | create_texpr(member(UId,ID),pred,[],UIdInSet), | |
| 1054 | rewrite_member_to_ge_le(UId,GlobalSet,GeLeConstraints), | |
| 1055 | create_texpr(GeLeConstraints,pred,[],GeLeTexpr), | |
| 1056 | create_implication(UIdInSet,GeLeTexpr,Direction1), | |
| 1057 | create_implication(GeLeTexpr,UIdInSet,Direction2), | |
| 1058 | ||
| 1059 | create_forall([UId],Direction1,FA1), | |
| 1060 | create_forall([UId],Direction2,FA2), | |
| 1061 | Constraint = conjunct(FA1,FA2). | |
| 1062 | ||
| 1063 | rewrite_global_set_nat_or_int_value(b(value(global_set('NATURAL')),set(integer),Info), Out) :- | |
| 1064 | !, | |
| 1065 | Out = b(integer_set('NATURAL'),set(integer),Info). | |
| 1066 | rewrite_global_set_nat_or_int_value(b(value(global_set('NATURAL1')),set(integer),Info), Out) :- | |
| 1067 | !, | |
| 1068 | Out = b(integer_set('NATURAL1'),set(integer),Info). | |
| 1069 | rewrite_global_set_nat_or_int_value(b(value(global_set('NAT')),set(integer),Info), Out) :- | |
| 1070 | !, | |
| 1071 | Out = b(integer_set('NAT'),set(integer),Info). | |
| 1072 | rewrite_global_set_nat_or_int_value(b(value(global_set('NAT1')),set(integer),Info), Out) :- | |
| 1073 | !, | |
| 1074 | Out = b(integer_set('NAT1'),set(integer),Info). | |
| 1075 | rewrite_global_set_nat_or_int_value(b(value(global_set('INT')),set(integer),Info), Out) :- | |
| 1076 | !, | |
| 1077 | Out = b(integer_set('INT'),set(integer),Info). | |
| 1078 | rewrite_global_set_nat_or_int_value(In, In). | |
| 1079 | ||
| 1080 | rewrite_member_to_ge_le(ID,Set,Constraint) :- | |
| 1081 | get_texpr_expr(Set,interval(Low,High)), | |
| 1082 | create_texpr(greater_equal(ID,Low),pred,[],Lower), | |
| 1083 | create_texpr(greater_equal(High,ID),pred,[],Higher), | |
| 1084 | Constraint = conjunct(Lower,Higher). | |
| 1085 | rewrite_member_to_ge_le(ID,Set,Constraint) :- | |
| 1086 | rewrite_global_set_nat_or_int_value(Set, NSet), | |
| 1087 | get_texpr_expr(NSet,integer_set(Kind)), % no cut here see rule below | |
| 1088 | bzero(BZero), bone(BOne), bminint(MinInt), bmaxint(MaxInt), | |
| 1089 | create_texpr(greater_equal(ID,LowerBound),pred,[],Lower), | |
| 1090 | create_texpr(greater_equal(UpperBound,ID),pred,[],Higher), | |
| 1091 | Constraint = conjunct(Lower,Higher), | |
| 1092 | (Kind = 'NAT' -> LowerBound = BZero, UpperBound = MaxInt ; | |
| 1093 | Kind = 'NAT1' -> LowerBound = BOne, UpperBound = MaxInt ; | |
| 1094 | Kind = 'INT' -> LowerBound = MinInt, UpperBound = MaxInt). | |
| 1095 | rewrite_member_to_ge_le(ID,Set,Constraint) :- | |
| 1096 | rewrite_global_set_nat_or_int_value(Set, NSet), | |
| 1097 | get_texpr_expr(NSet,integer_set(Kind)), !, | |
| 1098 | bzero(BZero), bone(BOne), | |
| 1099 | (Kind = 'NATURAL' -> Constraint = greater_equal(ID,BZero) ; | |
| 1100 | Kind = 'NATURAL1' -> Constraint = greater_equal(ID,BOne)). | |
| 1101 | ||
| 1102 | bzero(b(integer(0),integer,[])). | |
| 1103 | bone(b(integer(1),integer,[])). | |
| 1104 | bminint(b(min_int,integer,[])). | |
| 1105 | bmaxint(b(max_int,integer,[])). |