| 1 | % (c) 2021-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 | :- module(quantifier_instantiation, [instantiate_quantifiers/3, | |
| 5 | instantiate_quantifier_possible/7, | |
| 6 | instantiate_exists_to_list/5]). | |
| 7 | ||
| 8 | :- use_module(library(lists)). | |
| 9 | :- use_module(library(ordsets), [ord_intersect/2, list_to_ord_set/2]). | |
| 10 | :- use_module(library(avl), [avl_to_list/2]). | |
| 11 | ||
| 12 | :- use_module(smt_solvers_interface(set_rewriter)). | |
| 13 | :- use_module(probsrc(preferences), [temporary_set_preference/2, | |
| 14 | reset_temporary_preference/1]). | |
| 15 | :- use_module(probsrc(b_global_sets), [lookup_global_constant/2, enumerated_set/1, | |
| 16 | list_contains_unfixed_deferred_set_id/1]). | |
| 17 | :- use_module(probsrc(bsyntaxtree), [get_texpr_type/2, | |
| 18 | find_identifier_uses/3, | |
| 19 | get_texpr_expr/2, | |
| 20 | conjunct_predicates/2, | |
| 21 | conjunction_to_list/2, | |
| 22 | replace_ids_by_exprs/4, | |
| 23 | select_member_in_conjunction/3, | |
| 24 | safe_create_texpr/4, | |
| 25 | disjunct_predicates/2, | |
| 26 | get_texpr_id/2, | |
| 27 | create_implication/3, | |
| 28 | is_membership_or_equality/3, | |
| 29 | syntaxtransformation_det/5]). | |
| 30 | :- use_module(probsrc(tools_meta),[safe_time_out/3]). | |
| 31 | :- use_module(probsrc(b_interpreter), [b_compute_expression_nowf/6]). | |
| 32 | :- use_module(probsrc(error_manager), [add_internal_error/2, | |
| 33 | enter_new_error_scope/2, | |
| 34 | exit_error_scope/3, | |
| 35 | enumeration_warning_occured_in_error_scope/0, | |
| 36 | clear_enumeration_warning_in_error_scope/1]). | |
| 37 | :- use_module(probsrc(performance_messages), [perfmessage_bexpr/3,perfmessage/3, perfmessage/4]). | |
| 38 | :- use_module(probsrc(module_information), [module_info/2]). | |
| 39 | :- use_module(probsrc(debug), [debug_mode/1]). | |
| 40 | ||
| 41 | :- module_info(group, smt_solvers). | |
| 42 | :- module_info(description, 'This module implements transformations to simplify SMT-LIB translations.'). | |
| 43 | ||
| 44 | %% instantiate_quantifiers(+Options, +Ast, -AstOpt). | |
| 45 | % Options: | |
| 46 | % - instantiate_quantifier_limit(Limit) | |
| 47 | % - not_instantiate_unfixed_deferred_sets (necessary for Z3 since unfixed deferred set ids are invented by ProB) | |
| 48 | instantiate_quantifiers(Options, Ast, AstOpt) :- | |
| 49 | instantiate_quantifiers(Options, [], Ast, AstOpt). %bsyntaxtree:check_ast(AstOpt). | |
| 50 | ||
| 51 | instantiate_quantifiers(Options, ScopeIds, Ast, AstOpt) :- | |
| 52 | Ast = b(Expr,Type,Info), | |
| 53 | !, | |
| 54 | (%contains_no_quantifiers(Expr) -> AstOpt=Ast | |
| 55 | Type \= pred -> AstOpt = Ast % do we want to instantiate quantifiers inside set comprehensions / bool ...? | |
| 56 | ? | ; instantiate_quantifiers_e(Expr, Type, Info, Options, ScopeIds, NExpr) |
| 57 | -> safe_create_texpr(NExpr, Type, Info, AstOpt) | |
| 58 | ; add_internal_error('Call failed: ',instantiate_quantifiers_e(Expr, Type, Info, Options, ScopeIds, _)), | |
| 59 | AstOpt=Ast | |
| 60 | ). | |
| 61 | instantiate_quantifiers(_, _, L, R) :- | |
| 62 | add_internal_error('Not a B AST:',instantiate_quantifiers(_, _, L, R) ), | |
| 63 | R = L. | |
| 64 | ||
| 65 | instantiate_quantifiers_e(forall(TIDs,LHS,RHS), pred, Info, Options, ScopeIds, Res) :- | |
| 66 | instantiate_quantifier_possible(forall(TIDs,LHS,RHS), pred, Info, Options, ScopeIds, NOptions, TRes), | |
| 67 | ( TRes == truth | |
| 68 | -> Res = truth % no instantiation found, universal quantification is true | |
| 69 | ; contains_quantifiers_e(impliation(LHS,RHS)) -> instantiate_quantifiers(NOptions, ScopeIds, TRes, b(Res,pred,_)) | |
| 70 | ; get_texpr_expr(TRes,Res) % no quantifiers, no need to traverse | |
| 71 | ). | |
| 72 | instantiate_quantifiers_e(exists(TIDs,LHS), pred, Info, Options, ScopeIds, Res) :- | |
| 73 | instantiate_quantifier_possible(exists(TIDs,LHS), pred, Info, Options, ScopeIds, NOptions, TRes), | |
| 74 | ( TRes == falsity | |
| 75 | -> Res = falsity % no instantiation found, existential quantification is false | |
| 76 | ; contains_quantifiers(LHS) -> instantiate_quantifiers(NOptions, ScopeIds, TRes, b(Res,pred,_)) | |
| 77 | ; get_texpr_expr(TRes,Res) % no quantifiers, no need to traverse | |
| 78 | ). | |
| 79 | instantiate_quantifiers_e(Expr, _, _, Options, ScopeIds, Res) :- | |
| 80 | % TODO: only proceed if we do not have a top-level exists/forall | |
| 81 | %hit_profiler:add_profile_hit(Expr), | |
| 82 | syntaxtransformation_det(Expr,Subs,_,NSubs,NExpr), | |
| 83 | !, | |
| 84 | %maplist(instantiate_quantifiers(Options, ScopeIds),Subs,NSubs), | |
| 85 | l_instantiate_quantifiers(Subs,Options,ScopeIds,NSubs), | |
| 86 | Res = NExpr. | |
| 87 | instantiate_quantifiers_e(Expr, _, _, _, ScopeIds, Res) :- | |
| 88 | add_internal_error('Unknown AST node:', instantiate_quantifiers_e(Expr, _, _, _, ScopeIds, Res)), | |
| 89 | Res = Expr. | |
| 90 | ||
| 91 | %contains_no_quantifiers(identifier(_)). | |
| 92 | %contains_no_quantifiers(integer(_)). | |
| 93 | %contains_no_quantifiers(string(_)). | |
| 94 | %contains_no_quantifiers(value(_)). | |
| 95 | ||
| 96 | % quick check if a predicate contains quantifiers at the outer-predicate level (not inside bool(.), ...) | |
| 97 | % check is applied to predicate before expansion; possibly avoiding costly traversal of thousands of conjuncts | |
| 98 | contains_quantifiers(b(E,pred,_)) :- contains_quantifiers_e(E). | |
| 99 | contains_quantifiers_e(negation(A)) :- contains_quantifiers(A). | |
| 100 | contains_quantifiers_e(conjunct(A,B)) :- (contains_quantifiers(A) -> true ; contains_quantifiers(B)). | |
| 101 | contains_quantifiers_e(disjunct(A,B)) :- (contains_quantifiers(A) -> true ; contains_quantifiers(B)). | |
| 102 | contains_quantifiers_e(implication(A,B)) :- (contains_quantifiers(A) -> true ; contains_quantifiers(B)). | |
| 103 | contains_quantifiers_e(equivalence(A,B)) :- (contains_quantifiers(A) -> true ; contains_quantifiers(B)). | |
| 104 | contains_quantifiers_e(forall(_,_,_)). | |
| 105 | contains_quantifiers_e(exists(_,_)). | |
| 106 | ||
| 107 | ||
| 108 | l_instantiate_quantifiers([],_,_,[]). | |
| 109 | l_instantiate_quantifiers([S1|TS],Options,ScopeIds,[NS1|NTS]) :- | |
| 110 | instantiate_quantifiers(Options,ScopeIds,S1,NS1), | |
| 111 | l_instantiate_quantifiers(TS,Options,ScopeIds,NTS). | |
| 112 | ||
| 113 | :- use_module(probsrc(bsyntaxtree), [get_texpr_ids/2]). | |
| 114 | instantiate_quantifier_possible(forall(TIDs,LHS,RHS), pred, Info, Options, ScopeIds, NOptions, Res) :- | |
| 115 | ? | instantiate_paras_possible(TIDs, LHS, forall, Info, Options, Ids, ScopeIds, List, RestLHS), |
| 116 | ( List == [] | |
| 117 | -> % no instantiation found, universal quantification is true | |
| 118 | Res = b(truth,pred,[]) | |
| 119 | ; length(List,Len), | |
| 120 | check_quantifier_limit(Options, Len, forall, Info, NOptions), | |
| 121 | !, | |
| 122 | create_implication(RestLHS, RHS, BODY),% translate:nested_print_bexpr(BODY),nl, | |
| 123 | % Note: it is important that List contains only ground values; otherwise findall will copy variables: | |
| 124 | findall(Vals, get_instantiation_value(Ids, List, Vals),Vs), | |
| 125 | maplist(replace_ids_by_exprs(BODY,Ids),Vs,Bodies), | |
| 126 | Bodies \== [], | |
| 127 | %Bodies = [B1|_], translate:print_bexpr(B1),nl, | |
| 128 | conjunct_predicates(Bodies, Res) | |
| 129 | ). | |
| 130 | instantiate_quantifier_possible(exists(TIDs,LHS), pred, Info, Options, ScopeIds, NOptions, Res) :- | |
| 131 | instantiate_quantifier_to_list(TIDs,LHS,exists,Info,Options,ScopeIds,NOptions,Bodies), | |
| 132 | disjunct_predicates(Bodies, Res). | |
| 133 | ||
| 134 | % try and instantiate an existential quantifier into a list of candidates | |
| 135 | % used e.g., in b_to_cnf to translate cardinality constraints | |
| 136 | % it is important that every disjunct represents a distinct candidate element | |
| 137 | instantiate_exists_to_list(TIDs,LHS,Info,Options,Bodies) :- | |
| 138 | instantiate_quantifier_to_list(TIDs,LHS,exists,Info,Options,[],_NOptions,Bodies). | |
| 139 | ||
| 140 | % instantiate a quantifier to list of body candidates, without conjoining/disjoining them | |
| 141 | instantiate_quantifier_to_list(TIDs,LHS,Kind,Info,Options,ScopeIds,NOptions,Bodies) :- | |
| 142 | ? | instantiate_paras_possible(TIDs, LHS, Kind, Info, Options, Ids, ScopeIds, List, BODY), |
| 143 | ( List == [] | |
| 144 | -> % no instantiation found, existential quantification is false | |
| 145 | Bodies = [] % falsity for disjunction | |
| 146 | ; length(List,Len), | |
| 147 | check_quantifier_limit(Options, Len, Kind, Info, NOptions), | |
| 148 | !, | |
| 149 | findall(Vals, get_instantiation_value(Ids, List, Vals),Vs), | |
| 150 | maplist(replace_ids_by_exprs(BODY,Ids),Vs,Bodies), | |
| 151 | Bodies \== [] | |
| 152 | ). | |
| 153 | ||
| 154 | % detect whether a quantifier expansion is possible | |
| 155 | instantiate_paras_possible(TIDs, LHS, Kind, Info, Options, Ids, ScopeIds, List, RestLHS) :- | |
| 156 | \+ possibly_reject_unfixed_deferred_set_id(TIDs, Options), | |
| 157 | (nonmember(instantiate_precisely_only,Options), | |
| 158 | instantiate_paras_by_membership(TIDs, LHS, Kind, Info, Options, Ids, ScopeIds, List, RestLHS) | |
| 159 | ; | |
| 160 | ? | instantiate_paras_comp_set(TIDs, LHS, Kind, Info, Options, Ids, ScopeIds, List, RestLHS)). |
| 161 | instantiate_paras_possible(TIDS, LHS, Kind, _, _Span, _, _, _, _) :- | |
| 162 | TIDS = [TID1|_], | |
| 163 | get_texpr_id(TID1,Id1), | |
| 164 | perfmessage_bexpr(Kind, ['Quantifier (',Kind,' over ',Id1,', ...) expansion not possible: '], LHS), | |
| 165 | fail. | |
| 166 | ||
| 167 | % try and instantiate by finding specific membership predicates or look at types | |
| 168 | instantiate_paras_by_membership([TID], LHS, _, _, Options, [Id], ScopeIds, ListOfValues, RestLHS) :- | |
| 169 | get_texpr_id(TID, Id), | |
| 170 | ( get_texpr_id(TID2, Id), | |
| 171 | is_membership_or_equality(MEM, TID2, Set), | |
| 172 | select_member_in_conjunction(MEM, LHS, TRestLHS) | |
| 173 | ; get_texpr_type(TID, Type), | |
| 174 | finite_base_type(Type, Set), | |
| 175 | TRestLHS = LHS | |
| 176 | ), | |
| 177 | rewrite_set_to_list_of_asts(Set, [Id|ScopeIds], Options, TListOfValues), | |
| 178 | !, | |
| 179 | ListOfValues = TListOfValues, | |
| 180 | RestLHS = TRestLHS. | |
| 181 | instantiate_paras_by_membership([TID1,TID2], LHS, _Kind, _, Options, [Id1,Id2], ScopeIds, ListOfPairs, RestLHS) :- | |
| 182 | get_texpr_id(TID1, Id1), | |
| 183 | get_texpr_id(TID2, Id2), | |
| 184 | Couple = b(couple(A,B),_,_), get_texpr_id(A,Id1), get_texpr_id(B,Id2), | |
| 185 | MEM = b(member(Couple,Set),pred,_), | |
| 186 | select_member_in_conjunction(MEM, LHS, RestLHS), | |
| 187 | rewrite_set_to_list_of_asts(Set, [Id1,Id2|ScopeIds], Options, ListOfValues), | |
| 188 | maplist(convert_to_couple, ListOfValues, ListOfPairs), | |
| 189 | !. | |
| 190 | instantiate_paras_by_membership(TIDS, LHS, _, _, Options, IdNames, ScopeIds, ListOfTuples, RestLHS) :- | |
| 191 | % !(x1,..xn).(x1:S1 & .. & xn:Sn & RestLHS => BODY) | #(x1,..xn).(x1:S1 & .. & xn:Sn & RestLHS) | |
| 192 | instantiate_paras_possible_nary_member(TIDS, LHS, IdNames, [], ScopeIds, Options, TListOfTuples, TRestLHS), | |
| 193 | !, | |
| 194 | ListOfTuples = TListOfTuples, | |
| 195 | RestLHS = TRestLHS. | |
| 196 | ||
| 197 | ||
| 198 | % try and instantiate by expanding a filtered comprehension set of possible parameter values | |
| 199 | % will be more precise by considering all constraints (e.g., symmetry breaking), but can have issues like time-outs, ... | |
| 200 | instantiate_paras_comp_set(TIDS, LHS, Kind, Info, Options, IdNames, _ScopeIds, ListOfTuples, RestLHS) :- | |
| 201 | % any other quantifier where domains are, e.g., defined in nested couples such as !(a,b,c).(0|->1|-a|->b|->c : S => BODY), also for exists | |
| 202 | get_couple_type_for_ids(TIDS, CType), | |
| 203 | get_id_names(TIDS, TIdNames), | |
| 204 | filter_lhs_distinct_from_ids(LHS, TIdNames, RelevantLHS, RestLHS), | |
| 205 | CompSet = b(comprehension_set(TIDS,RelevantLHS),set(CType),[]), | |
| 206 | find_identifier_uses(CompSet, [], UsedIds), | |
| 207 | ( create_global_state_bindings(UsedIds, Bindings) | |
| 208 | -> true | |
| 209 | ; % cannot instantiate due to free variables that are not quantified | |
| 210 | fail | |
| 211 | ), | |
| 212 | % Default timeout 100ms, can be overridden with expansion_time_out option | |
| 213 | % write('TRY EXPANDING: '),nl,translate:print_bexpr(CompSet),nl, | |
| 214 | compute_instantiations_from_compset(Kind,Options,CompSet, Bindings, PrecomputedVals,Options, Info), | |
| 215 | !, | |
| 216 | IdNames = TIdNames, | |
| 217 | ( PrecomputedVals == [] | |
| 218 | -> ListOfTuples = [] % no instantiation found, quantifier is false/true | |
| 219 | ; PrecomputedVals = avl_set(Avl), | |
| 220 | avl_to_list(Avl, AvlList), | |
| 221 | ? | avl_list_to_list_of_asts(CType, AvlList, [], ListOfValues), |
| 222 | (TIDS = [_] % single identifier | |
| 223 | -> ListOfTuples=ListOfValues | |
| 224 | ; reverse(TIDS, RTIDS), | |
| 225 | couples_to_list_of_tuples(ListOfValues, RTIDS, ListOfTuples) | |
| 226 | ) | |
| 227 | ). | |
| 228 | ||
| 229 | possibly_reject_unfixed_deferred_set_id(TIDS, Options) :- | |
| 230 | member(not_instantiate_unfixed_deferred_sets, Options), | |
| 231 | list_contains_unfixed_deferred_set_id(TIDS). | |
| 232 | ||
| 233 | :- use_module(probsrc(custom_explicit_sets),[try_expand_and_convert_to_avl_with_check/3]). | |
| 234 | :- use_module(probsrc(kernel_tools),[ground_bexpr/1]). | |
| 235 | compute_instantiations_from_compset(Kind,Options,CompSet, Bindings, PrecomputedVals,Options,Span) :- | |
| 236 | ground_bexpr(CompSet), % should now be always true | |
| 237 | temporary_set_preference(strict_raise_enum_warnings, false), | |
| 238 | enter_new_error_scope(ScopeID, compute_instantiations_from_compset), | |
| 239 | ( true | |
| 240 | ; clear_enumeration_warning_in_error_scope(ScopeID), | |
| 241 | fail | |
| 242 | ), | |
| 243 | ? | (member(expansion_time_out(Val),Options) -> TimeOutVal=Val ; TimeOutVal=100), |
| 244 | % things like !i.(i:dom(f) => f(x)=TRUE) cannot be expanded if f not fully known at the moment | |
| 245 | (debug_mode(on) -> format('Trying to expand (timeout ~w ms): ',[TimeOutVal]),translate:print_bexpr(CompSet),nl ; true), | |
| 246 | call_cleanup(safe_time_out( | |
| 247 | (b_compute_expression_nowf(CompSet, [], Bindings, TPrecomputedVals, | |
| 248 | 'SMT quantifier precomputation', 0), !, | |
| 249 | (enumeration_warning_occured_in_error_scope | |
| 250 | -> perfmessage(Kind,not_expanding_quantifier_due_to_enum_warning(Kind),Span) | |
| 251 | ; true) | |
| 252 | ), | |
| 253 | TimeOutVal, TimeOutRes), | |
| 254 | (exit_error_scope(ScopeID, _, compute_instantiations_from_compset), | |
| 255 | reset_temporary_preference(strict_raise_enum_warnings))), | |
| 256 | (TimeOutRes == time_out | |
| 257 | -> perfmessage(Kind,not_expanding_quantifier_due_to_timeout(Kind,TimeOutVal),Span), | |
| 258 | fail | |
| 259 | ; true), | |
| 260 | !, | |
| 261 | expand_computed_val(TPrecomputedVals,Kind,Options,PrecomputedVals,Span). | |
| 262 | ||
| 263 | :- use_module(probsrc(custom_explicit_sets),[is_interval_closure/3]). | |
| 264 | expand_computed_val(global_set(GS),Kind,Options,Res,Span) :- | |
| 265 | % for deferred sets: we check list_contains_unfixed_deferred_set_id above | |
| 266 | (enumerated_set(GS) -> true | |
| 267 | ; member(instantiate_deferred_sets,Options), % Z3 cannot deal with deferred set values, see test 2063 | |
| 268 | perfmessage(Kind,not_expanding_quantifier_with_global_deferred_set(Kind),GS,Span) | |
| 269 | ),!, | |
| 270 | try_expand_and_convert_to_avl_with_check(global_set(GS),Res,quantifier_instantiation(Kind)). | |
| 271 | % Should we expand some closures like intervals here? b_compute_expression_nowf probably has already tried to expand closures | |
| 272 | % However, intervals starting at size 101 are returned as symbolic: | |
| 273 | expand_computed_val(Closure,Kind,Options,Res,Span) :- | |
| 274 | is_interval_closure(Closure,Low,Up), | |
| 275 | number(Low), number(Up), | |
| 276 | Card is Up-Low+1, | |
| 277 | (member(instantiate_quantifier_limit(Lim),Options) -> true ; Lim=200), | |
| 278 | (Lim >= Card -> true | |
| 279 | ; perfmessage(Kind,not_expanding_interval(Kind,Card,limit(Lim)),Low:Up,Span), | |
| 280 | fail | |
| 281 | ), | |
| 282 | try_expand_and_convert_to_avl_with_check(Closure,Res,quantifier_instantiation(Kind)). | |
| 283 | expand_computed_val(Val,_,_,Val,_). | |
| 284 | ||
| 285 | ||
| 286 | % fails if containing any variable that is not a global constant | |
| 287 | create_global_state_bindings([], []). | |
| 288 | create_global_state_bindings([Id|T], [bind(Id,Val)|NT]) :- | |
| 289 | lookup_global_constant(Id, Val), | |
| 290 | create_global_state_bindings(T, NT). | |
| 291 | ||
| 292 | :- use_module(probsrc(tools),[split_list/4]). | |
| 293 | filter_lhs_distinct_from_ids(LHS, IdNames, RelevantLHS, RestLHS) :- | |
| 294 | conjunction_to_list(LHS, List), | |
| 295 | list_to_ord_set(IdNames,SIds), | |
| 296 | split_list(irrelevant_or_non_ground_conjunct(SIds),List,TList,RList), | |
| 297 | conjunct_predicates(RList, RelevantLHS), | |
| 298 | conjunct_predicates(TList, RestLHS). | |
| 299 | ||
| 300 | irrelevant_or_non_ground_conjunct(_,Conj) :- \+ ground_bexpr(Conj),!. | |
| 301 | irrelevant_or_non_ground_conjunct(IdNames,Conj) :- | |
| 302 | find_identifier_uses(Conj, [], UsedIds), | |
| 303 | \+ ord_intersect(UsedIds, IdNames). | |
| 304 | ||
| 305 | get_id_names([], []). | |
| 306 | get_id_names([b(identifier(IdName),_,_)|T], [IdName|NT]) :- | |
| 307 | get_id_names(T, NT). | |
| 308 | ||
| 309 | get_couple_type_for_ids([TID1], Type1) :- !, get_texpr_type(TID1, Type1). | |
| 310 | get_couple_type_for_ids([TID1,TID2|T], CType) :- | |
| 311 | get_texpr_type(TID1, Type1), | |
| 312 | get_texpr_type(TID2, Type2), | |
| 313 | get_couple_type_for_ids(T, couple(Type1,Type2), CType). | |
| 314 | ||
| 315 | get_couple_type_for_ids([], CType, CType). | |
| 316 | get_couple_type_for_ids([TID|T], Acc, CType) :- | |
| 317 | get_texpr_type(TID, Type), | |
| 318 | get_couple_type_for_ids(T, couple(Acc,Type), CType). | |
| 319 | ||
| 320 | % for quantifiers with n variables and each variable's domain is set by a simple membership | |
| 321 | instantiate_paras_possible_nary_member([], RestLHS, [], LAcc, _, _, LAcc, RestLHS). | |
| 322 | instantiate_paras_possible_nary_member([TID|T], LHS, [Id|IdNames], LAcc, ScopeIds, Options, ListOfPairs, RestLHS) :- | |
| 323 | get_texpr_id(TID,Id), | |
| 324 | TID = b(IdTerm,IdType,_), | |
| 325 | ? | get_member_for_id(IdTerm,IdType,LHS,Set,RestLHS1), |
| 326 | NScopeIds = [Id|ScopeIds], | |
| 327 | rewrite_set_to_list_of_asts(Set, NScopeIds, Options, ListOfValues), | |
| 328 | ( LAcc == [] | |
| 329 | -> instantiate_paras_possible_nary_member(T, RestLHS1, IdNames, ListOfValues, NScopeIds, Options, ListOfPairs, RestLHS) | |
| 330 | ; create_cartesian_product_list(LAcc, ListOfValues, NLAcc), | |
| 331 | instantiate_paras_possible_nary_member(T, RestLHS1, IdNames, NLAcc, NScopeIds, Options, ListOfPairs, RestLHS) | |
| 332 | ). | |
| 333 | ||
| 334 | get_member_for_id(IdTerm,IdType,LHS,Set,RestLHS) :- | |
| 335 | MEM = b(member(b(IdTerm,IdType,_),Set),pred,_), | |
| 336 | select_member_in_conjunction(MEM, LHS, RestLHS). | |
| 337 | % we could try and constrain sets like intervals further, probably better to use instantiate_paras_comp_set | |
| 338 | get_member_for_id(_Id,IdType,LHS,Set,Rest) :- Rest=LHS, | |
| 339 | (IdType = global(GS) | |
| 340 | -> Set = b(value(global_set(GS)),set(IdType),[]) % we have a finite enumerated or def. set as type | |
| 341 | ; IdType = boolean | |
| 342 | -> Set = b(boolean_set,set(IdType),[]) | |
| 343 | ). | |
| 344 | ||
| 345 | ||
| 346 | % rewrite (nested) couples to a list of lists with [val1,..,valn] | |
| 347 | couples_to_list_of_tuples([], _, []). | |
| 348 | couples_to_list_of_tuples([b(value(ValueCouple),CoupleType,_)|T], RTIDS, [ListOfAsts|NT]) :- | |
| 349 | value_couple_to_list_of_asts(ValueCouple, RTIDS, CoupleType, ListOfAsts), | |
| 350 | couples_to_list_of_tuples(T, RTIDS, NT). | |
| 351 | ||
| 352 | % assuming that couples are left-associative | |
| 353 | value_couple_to_list_of_asts((VCouple,Value), [_|TRTIDS], couple(CoupleType,VType), ListOfAsts) :- | |
| 354 | VCouple = (_,_), | |
| 355 | !, | |
| 356 | value_couple_to_list_of_asts(VCouple, TRTIDS, CoupleType, TListOfAst), | |
| 357 | append(TListOfAst, [b(value(Value),VType,[])], ListOfAsts). | |
| 358 | value_couple_to_list_of_asts((Value1,Value2), [_], couple(VType1,VType2), ListOfAsts) :- | |
| 359 | ListOfAsts = [b(couple(b(value(Value1),VType1,[]),b(value(Value2),VType2,[])),couple(VType1,VType2),[])]. | |
| 360 | value_couple_to_list_of_asts((Value1,Value2), [_,_], couple(VType1,VType2), ListOfAsts) :- | |
| 361 | ListOfAsts = [b(value(Value1),VType1,[]),b(value(Value2),VType2,[])]. | |
| 362 | ||
| 363 | % create a list of lists with [val1,..,valn] | |
| 364 | create_cartesian_product_list(ListOfValues1, ListOfValues2, ListOfPairs) :- | |
| 365 | create_cartesian_product_list(ListOfValues1, ListOfValues2, [], ListOfPairs). | |
| 366 | ||
| 367 | create_cartesian_product_list([], _, Acc, Acc). | |
| 368 | create_cartesian_product_list([Val1|T], ListOfValues2, Acc, ListOfPairs) :- | |
| 369 | create_cartesian_product_list_val(Val1, ListOfValues2, Acc, NAcc), | |
| 370 | create_cartesian_product_list(T, ListOfValues2, NAcc, ListOfPairs). | |
| 371 | ||
| 372 | create_cartesian_product_list_val(_, [], Acc, Acc). | |
| 373 | create_cartesian_product_list_val(ValList, [Val2|T], Acc, NAcc) :- | |
| 374 | is_list(ValList), | |
| 375 | !, | |
| 376 | append(ValList, [Val2], NValList), | |
| 377 | create_cartesian_product_list_val(ValList, T, [NValList|Acc], NAcc). | |
| 378 | create_cartesian_product_list_val(Val1, [Val2|T], Acc, NAcc) :- | |
| 379 | create_cartesian_product_list_val(Val1, T, [[Val1,Val2]|Acc], NAcc). | |
| 380 | ||
| 381 | finite_base_type(boolean,b(boolean_set,set(boolean),[])). | |
| 382 | finite_base_type(couple(TA,TB),b(cartesian_product(VA,VB),set(couple(TA,TB)),[])) :- | |
| 383 | finite_base_type(TA,VA), | |
| 384 | finite_base_type(TB,VB). | |
| 385 | % TODO: add more, e.g., enumerated sets | |
| 386 | ||
| 387 | check_quantifier_limit(Options, Len, Kind, Span, NewOptions) :- | |
| 388 | ? | select(instantiate_quantifier_limit(Limit),Options,NO), |
| 389 | Len \== 0, | |
| 390 | !, | |
| 391 | ( Len =< Limit | |
| 392 | -> perfmessage(good(Kind),expanding_quantifier(Len,limit(Limit)),Span), | |
| 393 | NewLimit is Limit // Len, | |
| 394 | NewOptions = [instantiate_quantifier_limit(NewLimit)|NO] | |
| 395 | ; perfmessage(Kind,not_expanding_quantifier(Kind,Len,limit(Limit)),Span), | |
| 396 | fail | |
| 397 | ). | |
| 398 | check_quantifier_limit(O, _, _, _, O). | |
| 399 | ||
| 400 | % TO DO: detect more cases ? | |
| 401 | convert_to_couple(b(value(V),couple(T1,T2),I), [BV1,BV2]) :- | |
| 402 | nonvar(V), | |
| 403 | V = (V1,V2), | |
| 404 | !, | |
| 405 | BV1 = b(value(V1),T1,I), | |
| 406 | BV2 = b(value(V2),T2,I). | |
| 407 | convert_to_couple(b(couple(V1,V2),_,_), [V1,V2]). | |
| 408 | ||
| 409 | % if instantiate_quantifier_possible then this can be used to retrieve values for expansion | |
| 410 | get_instantiation_value([_], List, Res) :- !, Res=[Val], | |
| 411 | ? | member(Val,List). |
| 412 | get_instantiation_value(L, List, ValList) :- | |
| 413 | length(L, Len), | |
| 414 | Len > 1, | |
| 415 | length(ValList, Len), | |
| 416 | ? | member(ValList, List). |
| 417 | ||
| 418 | ||
| 419 |