| 1 | % (c) 2020-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(well_def_prover, [prove_po/3]). | |
| 6 | ||
| 7 | :- use_module(probsrc(module_information),[module_info/2]). | |
| 8 | :- module_info(group,well_def_prover). | |
| 9 | :- module_info(description,'This module proves WD POs.'). | |
| 10 | ||
| 11 | :- use_module(library(avl)). | |
| 12 | :- use_module(library(lists)). | |
| 13 | ||
| 14 | :- use_module(wdsrc(well_def_hyps),[get_hyp_var_type/3, portray_hyps/1, get_clash_renaming_subst/2, | |
| 15 | is_hyp_var/2, is_finite_type_for_wd/2, add_new_hyp_any_vars/3, negate_op/2, | |
| 16 | hyps_inconsistent/1, | |
| 17 | push_normalized_hyp/3, push_and_rename_normalized_hyp/3]). | |
| 18 | ||
| 19 | :- use_module(wdsrc(well_def_tools), [rename_norm_term/3, member_in_norm_conjunction/2, not_occurs/2, occurs/2]). | |
| 20 | :- use_module(probsrc(debug)). | |
| 21 | :- use_module(probsrc(error_manager),[add_error/3, add_internal_error/2]). | |
| 22 | ||
| 23 | :- use_module(probsrc(custom_explicit_sets),[domain_of_explicit_set_wf/3, equal_avl_tree/2, | |
| 24 | range_of_explicit_set_wf/3, | |
| 25 | invert_explicit_set/2,check_interval_in_custom_set/4, is_interval_closure/5, | |
| 26 | check_avl_in_interval/3, check_avl_subset/2, is_one_element_avl/2, | |
| 27 | avl_is_interval/3, | |
| 28 | expand_custom_set_to_list/2, quick_definitely_maximal_set_avl/1, | |
| 29 | expand_and_convert_to_avl_set/4, safe_is_avl_sequence/1, is_avl_partial_function/1]). | |
| 30 | ||
| 31 | :- load_files(library(system), [when(compile_time), imports([environ/2])]). | |
| 32 | ||
| 33 | % PROVING: | |
| 34 | % -------- | |
| 35 | ||
| 36 | ||
| 37 | % some more rules are covered in process_sequent_aux of prove_sequent/3 | |
| 38 | prove_po(truth,_,truth). | |
| 39 | prove_po(_NormTarget,Hyps,false_hyp) :- hyps_inconsistent(Hyps). | |
| 40 | prove_po(NormTarget,hyp_rec(AVL,_),hyp) :- avl_fetch(NormTarget,AVL). | |
| 41 | prove_po(member(X,Y),Hyps,mem(PT)) :- % Y is usually domain(Func) | |
| 42 | simplify_expr_loop(Y,Hyps,SY), | |
| 43 | simplify_expr_loop(X,Hyps,SX), | |
| 44 | check_member_of_set(SY,SX,Hyps,PT). | |
| 45 | prove_po(not_member(X,Y),Hyps,mem(PT)) :- | |
| 46 | simplify_expr_loop(Y,Hyps,SY), | |
| 47 | simplify_expr_loop(X,Hyps,SX), | |
| 48 | check_not_member_of_set(SY,SX,Hyps,PT). | |
| 49 | prove_po(finite(Set),Hyp,finite_set(PT)) :- check_finite(Set,Hyp,PT). | |
| 50 | prove_po(not_equal(A,B),Hyp,not_equal) :- | |
| 51 | simplify_expr_loop(A,Hyp,SA), | |
| 52 | simplify_expr_loop(B,Hyp,SB), | |
| 53 | check_not_equal(SA,SB,Hyp). | |
| 54 | prove_po(equal(A,B),Hyp,equal) :- % not generated by our POG | |
| 55 | simplify_expr_loop(A,Hyp,SA), | |
| 56 | simplify_expr_loop(B,Hyp,SB), | |
| 57 | check_equal(SA,SB,Hyp,_). | |
| 58 | prove_po(greater(A,B),Hyp,PT) :- prove_po(less(B,A),Hyp,PT). | |
| 59 | prove_po(greater_equal(A,B),Hyp,greater_equal) :- % print(check_leq(B,A)),nl, | |
| 60 | check_leq(B,A,Hyp). | |
| 61 | prove_po(less_equal(A,B),Hyp,less_equal) :- | |
| 62 | check_leq(A,B,Hyp). | |
| 63 | %prove_po(less_equal_real(A,B),Hyp,less_equal_real) :- | |
| 64 | % check_leq(A,B,Hyp). % TODO: check that all proof rules are sound for reals, ditto for less | |
| 65 | prove_po(less(A,B),Hyp,less) :- | |
| 66 | check_leq(A,B,Hyp),!, | |
| 67 | check_not_equal(A,B,Hyp). | |
| 68 | prove_po(subset(A,B),Hyp,PT) :- | |
| 69 | simplify_expr_loop(A,Hyp,SA), simplify_expr_loop(B,Hyp,SB), | |
| 70 | check_is_subset(SA,SB,Hyp,PT). | |
| 71 | prove_po(subset_strict(A,B),Hyp,subset_strict(PT)) :- | |
| 72 | simplify_expr_loop(A,Hyp,SA), simplify_expr_loop(B,Hyp,SB), | |
| 73 | check_is_subset_strict(SA,SB,Hyp,PT). | |
| 74 | prove_po(not_subset_strict(A,B),Hyp,not_subset_strict(PT)) :- | |
| 75 | simplify_expr_loop(A,Hyp,SA), simplify_expr_loop(B,Hyp,SB), | |
| 76 | check_not_is_subset_strict(SA,SB,Hyp,PT). | |
| 77 | prove_po(not_subset(A,B),Hyp,not_subset(PT)) :- | |
| 78 | simplify_expr_loop(A,Hyp,SA), simplify_expr_loop(B,Hyp,SB), | |
| 79 | check_not_subset(SA,SB,Hyp,PT). | |
| 80 | prove_po(conjunct(A,B),Hyp,conj(T1,T2)) :- % generated by Rodin | |
| 81 | prove_po(A,Hyp,T1), | |
| 82 | !, | |
| 83 | prove_po(B,Hyp,T2). | |
| 84 | prove_po(disjunct(A,B),Hyp,conj(T1,T2)) :- % could be generated by Rodin | |
| 85 | (% push_normalized_hyp(NotB,Hyp,Hyp2), % % OR_R rule allows to add not(B) as hypothesis | |
| 86 | prove_po(A,Hyp,T1) -> true | |
| 87 | ; prove_po(B,Hyp,T2)). % OR_R rule allows to add not(A) as hypothesis, this is done in prove_sequent_goal | |
| 88 | prove_po(implication(A,B),Hyp,imply(T2)) :- % generated by Rodin; now treated in prove_sequent_goal | |
| 89 | % also generated for power_of_real | |
| 90 | (prove_negated_po(A,Hyp,PT) -> T2=false_lhs(PT) | |
| 91 | ; debug_println(19,not_pushing_lhs_for_implication(A)), | |
| 92 | %push_normalized_hyp(A,Hyp,Hyp2), % TODO: activate this | |
| 93 | prove_po(B,Hyp,T2) | |
| 94 | ). | |
| 95 | prove_po(exists([$(B0)],forall([$(X)],member($(X),Set),less_equal($(X),$(B0)))),Hyp,finite_max(PT)) :- X \= B0, | |
| 96 | % generated by Rodin for max(Set) | |
| 97 | debug_println(19,checking_finite_for_max(Set)), | |
| 98 | check_finite(Set,Hyp,PT). | |
| 99 | prove_po(exists([$(B0)],forall([$(X)],member($(X),Set),less_equal($(B0),$(X)))),Hyp,finite_min(PT)) :- X \= B0, | |
| 100 | % generated by Rodin for min(Set) | |
| 101 | debug_println(19,checking_finite_for_min(Set)), | |
| 102 | check_finite(Set,Hyp,PT). | |
| 103 | prove_po(negation(Goal),Hyp,negation(PT)) :- prove_negated_po(Goal,Hyp,PT). | |
| 104 | %prove_po(NT,_,_) :- format('Unproven by WD Prover: ~w~n~n',[NT]),fail. | |
| 105 | ||
| 106 | % some redundancy wrt negate_hyp; but negate_hyp currently does not go inside conjunction | |
| 107 | prove_negated_po(falsity,_,falsity) :- !. | |
| 108 | prove_negated_po(disjunct(A,B),Hyp,negdisj(T1,T2)) :- !, | |
| 109 | (prove_negated_po(A,Hyp,T1) -> prove_negated_po(B,Hyp,T2)). | |
| 110 | prove_negated_po(conjunct(A,B),Hyp,negconj(T1,T2)) :- !, % could be generated by Rodin | |
| 111 | (prove_negated_po(A,Hyp,T1) -> true | |
| 112 | ; prove_negated_po(B,Hyp,T2)). % we could add not(A) as hypothesis, | |
| 113 | prove_negated_po(negation(Goal),Hyp,negation(PT)) :-!, prove_po(Goal,Hyp,PT). | |
| 114 | prove_negated_po(OP,Hyp,negated_op(PT)) :- negate_op(OP,NOP), prove_po(NOP,Hyp,PT). | |
| 115 | ||
| 116 | ||
| 117 | simple_value(Nr) :- number(Nr). | |
| 118 | simple_value('$'(_)). | |
| 119 | simple_value(boolean_true). | |
| 120 | simple_value(boolean_false). | |
| 121 | simple_value(record_field('$'(_),_)). | |
| 122 | simple_value(value(_)). | |
| 123 | simple_value(string(_)). | |
| 124 | simple_value(function(F,_)) :- simple_value(F). | |
| 125 | simple_value(couple(A,B)) :- simple_value(A), simple_value(B). | |
| 126 | ||
| 127 | %get_set_of_possible_values(X,Hyps,XSet) :- | |
| 128 | % if(try_get_set_of_possible_values(X,Hyps,R), XSet=R, | |
| 129 | % XSet=set_extension([X])). % was typeset | |
| 130 | ||
| 131 | try_get_set_of_possible_values(Nr,Hyps,R,Hyps) :- number(Nr),!,R=interval(Nr,Nr). | |
| 132 | try_get_set_of_possible_values(X,Hyps,R,Hyps) :- | |
| 133 | avl_fetch_binop_from_hyps_no_loop_check(X,equal,Hyps,Nr), number(Nr),!, % TODO: also treat is_explicit_value | |
| 134 | R=interval(Nr,Nr). | |
| 135 | try_get_set_of_possible_values(X,Hyps,XSet,Hyps2) :- | |
| 136 | avl_fetch_worthwhile_mem_from_hyps(X,Hyps,XSet1,Hyps1), | |
| 137 | (improve_integer_set_precision(X,XSet1,Hyps1,XSet,Hyps2) | |
| 138 | -> true ; Hyps2=Hyps1, XSet=XSet1). | |
| 139 | try_get_set_of_possible_values(X,Hyps,Res,Hyps3) :- | |
| 140 | avl_fetch_equal_from_hyps(X,Hyps,X2,Hyps1), | |
| 141 | quick_not_occurs_check(X,X2), | |
| 142 | rewrite_local_loop_check(X,try_get_set_of_possible_values,X2,Hyps1,Hyps2), | |
| 143 | (X2='$'(_) -> X = '$'(_) ; true), % avoid rewriting x -> card(...) -> x; TO DO: better cyclic equality prevention | |
| 144 | try_get_set_of_possible_values(X2,Hyps2,Res,Hyps3), !. | |
| 145 | try_get_set_of_possible_values(function(Func,Args),Hyps,RangeSet,Hyps2) :- !, | |
| 146 | (get_range_or_superset(Func,Hyps,RangeSet,Hyps2) -> true | |
| 147 | ; rewrite_function_application(Func,Args,Hyps,Result,Hyps1), % maybe put this first? | |
| 148 | try_get_set_of_possible_values(Result,Hyps1,RangeSet,Hyps2)). | |
| 149 | try_get_set_of_possible_values(first(Seq),Hyps,RangeSet,Hyps2) :- !, % first(S) === S(1) | |
| 150 | get_range_or_superset(Seq,Hyps,RangeSet,Hyps2). | |
| 151 | try_get_set_of_possible_values(last(Seq),Hyps,RangeSet,Hyps2) :- !, % last(S) === S(size(S)) | |
| 152 | get_range_or_superset(Seq,Hyps,RangeSet,Hyps2). | |
| 153 | % TO DO other sequence operations | |
| 154 | try_get_set_of_possible_values(couple(A,B),Hyps,cartesian_product(SA,SB),Hyps2) :- !, | |
| 155 | try_get_set_of_possible_values(A,Hyps,SA,Hyps1), | |
| 156 | try_get_set_of_possible_values(B,Hyps1,SB,Hyps2). | |
| 157 | try_get_set_of_possible_values(max(set_extension([V1,V2|_])),H,'NATURAL',H) :- % max({x,-x}) >= 0 | |
| 158 | ( V1 = unary_minus(V2), \+ number(V1) -> true | |
| 159 | ; V2 = unary_minus(V1), \+ number(V2) -> true), !. % instead of NATURAL we could try and infer values for V1/V2 | |
| 160 | try_get_set_of_possible_values(max(Set),H,Set,H). | |
| 161 | try_get_set_of_possible_values(min(Set),H,Set,H). | |
| 162 | try_get_set_of_possible_values(mu(Set),H,Set,H). | |
| 163 | try_get_set_of_possible_values(external_function_call(Call,[Set]),H,Set,H) :- | |
| 164 | (Call = 'CHOOSE' -> true ; Call = 'MU'). | |
| 165 | try_get_set_of_possible_values(max_int,H,'NATURAL1',H). | |
| 166 | % TO DO: min_int | |
| 167 | try_get_set_of_possible_values(value(avl_set(A1)),Hyps,value(avl_set(A2)),Hyps) :- !, | |
| 168 | expand_and_convert_to_avl_set([avl_set(A1)],A2,get_set_of_possible_values,'WD(?)'). | |
| 169 | try_get_set_of_possible_values(add(X,Y),Hyps,Set,Hyps2) :- | |
| 170 | add_with_number(add(X,Y),A,Nr), | |
| 171 | try_get_set_of_possible_values(A,Hyps,ValA,Hyps2), | |
| 172 | add_to_value_set(ValA,Nr,Set),!. | |
| 173 | try_get_set_of_possible_values(minus(A,Nr),Hyps,Set,Hyps2) :- number(Nr), Nr1 is -Nr, | |
| 174 | try_get_set_of_possible_values(A,Hyps,ValA,Hyps2), | |
| 175 | add_to_value_set(ValA,Nr1,Set),!. | |
| 176 | % TO DO : add unary_minus, multiplication with nr | |
| 177 | try_get_set_of_possible_values(Seq,Hyps,Set,Hyps) :- | |
| 178 | infer_sequence_type_of_expr(Seq,Hyps,SeqType),!, | |
| 179 | (SeqType=seq1 -> Set=seq1(typeset) ; Set=seq(typeset)). % TO DO: examine type of list elements | |
| 180 | try_get_set_of_possible_values(X,Hyps,XSet,Hyps2) :- | |
| 181 | avl_fetch_binop_from_hyps(X,greater_equal,Hyps,Low,Hyps1), !, | |
| 182 | (avl_fetch_binop_from_hyps(X,less_equal,Hyps1,Up,Hyps2) -> XSet = interval(Low,Up) | |
| 183 | ; Low=0 -> XSet = 'NATURAL', Hyps2=Hyps1 | |
| 184 | ; number(Low),Low>0 -> XSet= 'NATURAL1', Hyps2=Hyps1). % TO DO: improve precision | |
| 185 | try_get_set_of_possible_values(X,Hyps,XSet,Hyps2) :- | |
| 186 | rewrite_integer(X,Hyps,X2,Hyps1),!, | |
| 187 | try_get_set_of_possible_values(X2,Hyps1,XSet,Hyps2). | |
| 188 | try_get_set_of_possible_values(size(A),Hyps,XSet,Hyps) :- | |
| 189 | (check_not_empty_set(A,Hyps) -> XSet = 'NATURAL1' ; XSet='NATURAL'). | |
| 190 | try_get_set_of_possible_values(card(A),Hyps,XSet,Hyps) :- | |
| 191 | (check_not_empty_set(A,Hyps) -> XSet = 'NATURAL1' ; XSet='NATURAL'). | |
| 192 | try_get_set_of_possible_values(if_then_else(_,A,B),Hyps,R,Hyps) :- | |
| 193 | (try_get_set_of_possible_values(A,Hyps,AV,Hyps1) | |
| 194 | -> try_get_set_of_possible_values(B,Hyps1,BV,Hyps2)), | |
| 195 | construct_union(AV,BV,Hyps2,R). | |
| 196 | try_get_set_of_possible_values(modulo(A,B),Hyps1,XSet,Hyps2) :- | |
| 197 | number(B), B>0, | |
| 198 | B1 is B-1, | |
| 199 | XSet1 = interval(0,B1), % value of A mod B must be in 0..B1 | |
| 200 | % note: this also holds in z_or_tla_minor_mode, we have (-3) mod 2 = 1 | |
| 201 | (try_get_set_of_possible_values(A,Hyps1,XSet2,Hyps2), | |
| 202 | maximal_value(XSet2,Up) | |
| 203 | -> intersect_sets(XSet1,interval(0,Up),XSet) | |
| 204 | % we were able to reduce the interval further by finding possible upper-bound for A | |
| 205 | % we could call improve_upper_bound | |
| 206 | ; Hyps2=Hyps1, XSet=XSet1). | |
| 207 | try_get_set_of_possible_values(external_function_call(Name,Args),Hyps,R,Hyps) :- | |
| 208 | external_function_returns_sequence_type(Name,Args,Hyps,_,R). | |
| 209 | ||
| 210 | %try_get_set_of_possible_values(X,_,_,_) :- print(try_get_set_of_possible_values_failed(X)),nl,fail. | |
| 211 | % TO DO: more precise representation of open-ended intervals interval(Low,'$infinity')) | |
| 212 | % TO DO: intersect multiple solutions; e.g., intervals and >=, <= constraints | |
| 213 | ||
| 214 | maximal_value(interval(_,Up),Up). | |
| 215 | maximal_value(value(avl_set(A)),Up) :- avl_max(A,int(Up)). | |
| 216 | % TO DO: add avl_set | |
| 217 | ||
| 218 | ||
| 219 | is_integer_set(interval(_,_)). | |
| 220 | is_integer_set('NATURAL'). | |
| 221 | is_integer_set('NATURAL1'). | |
| 222 | is_integer_set('INTEGER'). | |
| 223 | % TO DO: add avl_set | |
| 224 | ||
| 225 | % detect sets which can profit from narrowing down: | |
| 226 | is_infinite__or_large_integer_set('NATURAL',0,inf). | |
| 227 | is_infinite__or_large_integer_set('NATURAL1',1,inf). | |
| 228 | %is_infinite__or_large_integer_set('INTEGER',-inf,inf). | |
| 229 | is_infinite__or_large_integer_set(interval(Low,max_int),Low,max_int). % one cannot prove a lot with max_int anyway!? | |
| 230 | ||
| 231 | % try and improve precision of integer set | |
| 232 | % limitation: only looks for one other hypotheses; maybe we should do this in well_defs_hyps.pl | |
| 233 | improve_integer_set_precision(X,XSet1,Hyps1,NewSet,Hyps3) :- | |
| 234 | is_integer_set(XSet1), | |
| 235 | avl_fetch_worthwhile_mem_from_hyps(X,Hyps1,XSet2,Hyps2), | |
| 236 | XSet2 \= XSet1, | |
| 237 | !, | |
| 238 | intersect_sets(XSet1,XSet2,XSet12), | |
| 239 | try_improve_interval(XSet12,X,Hyps2,NewSet,Hyps3). % TO DO: we could try and find another member | |
| 240 | % TO DO: also look at less_equal, greater_equal constraints | |
| 241 | improve_integer_set_precision(X,XSet1,Hyps1,NewSet,Hyps3) :- | |
| 242 | is_infinite__or_large_integer_set(XSet1,Low,LargeUp), | |
| 243 | avl_fetch_binop_from_hyps(X,less_equal,Hyps1,Up,Hyps2), | |
| 244 | Up \= LargeUp, % we really improve upon earlier value | |
| 245 | !, | |
| 246 | try_improve_interval(interval(Low,Up),X,Hyps2,NewSet,Hyps3). | |
| 247 | improve_integer_set_precision(X,XSet1,Hyps1,NewSet,Hyps2) :- | |
| 248 | try_improve_interval(XSet1,X,Hyps1,NewSet,Hyps2). | |
| 249 | ||
| 250 | try_improve_interval(interval(OldLow,OldUp),X,Hyps1,interval(NewLow,NewUp),Hyps2) :- !, | |
| 251 | improve_interval(X,OldLow,OldUp,Hyps1,NewLow,NewUp,Hyps2). | |
| 252 | try_improve_interval(Set,_,Hyps,Set,Hyps). | |
| 253 | ||
| 254 | % phase 1: try improve upper bound | |
| 255 | improve_interval(X,OldLow,OldUp,Hyps1,NewLow,NewUp,Hyps3) :- | |
| 256 | improve_upper_bound(X,OldUp,Hyps1,NewUp1,Hyps2),!, | |
| 257 | improve_interval(X,OldLow,NewUp1,Hyps2,NewLow,NewUp,Hyps3). | |
| 258 | improve_interval(X,OldLow,Up,Hyps1,NewLow,Up,Hyps2) :- | |
| 259 | improve_interval2(X,OldLow,Hyps1,NewLow,Hyps2). | |
| 260 | % | |
| 261 | improve_upper_bound(X,OldUp,Hyps1,NewUp,Hyps2) :- | |
| 262 | avl_fetch_binop_from_hyps(X,less_equal,Hyps1,Up,Hyps2), | |
| 263 | order_values(OldUp,Up,NewUp,OldUp), | |
| 264 | NewUp \= OldUp. | |
| 265 | ||
| 266 | % now try and improve lower bound: | |
| 267 | improve_interval2(X,OldLow,Hyps1,NewLow,Hyps3) :- | |
| 268 | improve_lower_bound(X,OldLow,Hyps1,Low1,Hyps2),!, | |
| 269 | improve_interval2(X,Low1,Hyps2,NewLow,Hyps3). | |
| 270 | improve_interval2(_,Low,Hyps,Low,Hyps). | |
| 271 | % | |
| 272 | improve_lower_bound(X,OldLow,Hyps1,NewLow,Hyps2) :- | |
| 273 | avl_fetch_binop_from_hyps(X,greater_equal,Hyps1,Low,Hyps2), | |
| 274 | order_values(Low,OldLow,OldLow,NewLow), | |
| 275 | NewLow \= OldLow. | |
| 276 | ||
| 277 | ||
| 278 | % try and intersect two sets: | |
| 279 | intersect_sets(interval(L1,U1),B,Res) :- !, intersect_interval(B,L1,U1,Res). | |
| 280 | intersect_sets(B,interval(L1,U1),Res) :- intersect_interval(B,L1,U1,Res). | |
| 281 | intersect_sets('NATURAL1','NATURAL','NATURAL1'). | |
| 282 | intersect_sets('NATURAL','NATURAL1','NATURAL1'). | |
| 283 | % TODO: support avl_set | |
| 284 | ||
| 285 | intersect_interval(interval(L2,U2),L1,U1,interval(L3,U3)) :- | |
| 286 | order_values(L1,L2,_,L3), % choose larger value as lower bound | |
| 287 | order_values(U1,U2,U3,_). % choose smaller value as upper bound | |
| 288 | intersect_interval('NATURAL1',L1,U1,interval(L3,U1)) :- order_values(L1,1,L3,_). | |
| 289 | intersect_interval('NATURAL',L1,U1,interval(L3,U1)) :- order_values(L1,0,L3,_). | |
| 290 | ||
| 291 | % order values for interval intersection | |
| 292 | order_values(N1,N2,R1,R2) :- number(N1),!, order_aux_nr(N2,N1,R1,R2). | |
| 293 | order_values(N1,N2,R1,R2) :- number(N2),!, order_aux_nr(N1,N2,R1,R2). | |
| 294 | order_values(min_int,N2,R1,R2) :- !, R1=min_int,R2=N2. | |
| 295 | order_values(max_int,N2,R1,R2) :- !, R1=N2,R2=max_int. | |
| 296 | order_values(N1,N2,N1,N2). % just choose N1 | |
| 297 | ||
| 298 | order_aux_nr(N2,N1,R1,R2) :- number(N2),!, | |
| 299 | (N2>N1 -> R1=N1,R2=N2 ; R1=N2,R2=N1). | |
| 300 | order_aux_nr(max_int,N1,R1,R2) :- N1 < 1, !, R1=N1, R2=max_int. | |
| 301 | order_aux_nr(_N2,N1,N1,N1). % choose the number as the bound | |
| 302 | ||
| 303 | ||
| 304 | ||
| 305 | add_to_value_set(interval(L,U),Nr,interval(L2,U2)) :- | |
| 306 | add_nr(L,Nr,L2), | |
| 307 | (add_nr(U,Nr,U2) -> true ; Nr =< 0, U2=U). % e.g., if U = size(x) we create an over-approximation | |
| 308 | add_to_value_set('NATURAL',1,'NATURAL1'). % TO DO: extend | |
| 309 | %add_to_value_set(value(avl_set(A1),Nr,value(avl_set(A2)) :- TO DO: add Nr to all values in A2 | |
| 310 | ||
| 311 | % adding a known number to an arithmetic expression; could be extended | |
| 312 | % this is mainly for dealing with index arithmetic for arrays | |
| 313 | add_nr(Nr1,ToAdd,Nr2) :- number(Nr1),!, Nr2 is Nr1+ToAdd. | |
| 314 | add_nr(minus(Expr,Nr1),ToAdd,Res) :- number(Nr1),!, Nr2 is Nr1-ToAdd, | |
| 315 | (Nr2=0 -> Res=Expr ; Res= minus(Expr,Nr2)). | |
| 316 | add_nr(add(Expr,Nr1),ToAdd,Res) :- number(Nr1),!, Nr2 is Nr1+ToAdd, | |
| 317 | (Nr2=0 -> Res=Expr ; Res= add(Expr,Nr2)). | |
| 318 | add_nr(add(Nr1,Expr),ToAdd,Res) :- number(Nr1),!, Nr2 is Nr1+ToAdd, | |
| 319 | (Nr2=0 -> Res=Expr ; Res= add(Expr,Nr2)). | |
| 320 | ||
| 321 | ||
| 322 | % check if an expression is a sequence | |
| 323 | check_is_sequence(El,Hyps) :- check_is_sequence(El,Hyps,_). | |
| 324 | check_is_non_empty_sequence(El,Hyps) :- check_is_sequence(El,Hyps,seq1). | |
| 325 | ||
| 326 | check_is_sequence(S,_,seq) :- is_empty_set_direct(S),!. | |
| 327 | check_is_sequence(El,Hyps,RequiredType) :- | |
| 328 | infer_sequence_type_of_expr(El,Hyps,Type), | |
| 329 | (Type=seq1 -> true ; RequiredType=seq -> true | |
| 330 | ; check_not_equal_empty_set(El,Hyps,_)), !. | |
| 331 | check_is_sequence(A,Hyps,RequiredType) :- | |
| 332 | avl_fetch_worthwhile_equal_from_hyps(A,Hyps,Value,Hyps2), | |
| 333 | check_is_sequence(Value,Hyps2,RequiredType), !. | |
| 334 | check_is_sequence(domain_restriction(Dom,S),Hyps,Res) :- !, | |
| 335 | is_interval(Dom,Hyps,1,N), | |
| 336 | check_is_sequence(S,Hyps,SeqType), | |
| 337 | (SeqType=seq1, check_leq(1,N,Hyps) -> Res=seq1 ; Res=seq). | |
| 338 | check_is_sequence(El,Hyps,RequiredType) :- | |
| 339 | avl_fetch_mem_or_struct(El,Hyps,Set,Hyps2), | |
| 340 | is_set_of_sequences_type(Set,Hyps2,Type), % should we move this to subset? dealt with in subset_transitivity_rule | |
| 341 | % required for :wd Right:seq(BOOL) & (Right/=[] => tail(Right)=res) in test 2018 | |
| 342 | (Type=seq1 -> true ; RequiredType=seq -> true | |
| 343 | ; check_not_equal_empty_set(El,Hyps2,_)), | |
| 344 | !. | |
| 345 | check_is_sequence(X,Hyps,RequiredType) :- try_get_set_of_possible_values(X,Hyps,XSet,Hyps2), | |
| 346 | (RequiredType==seq1 -> check_is_subset(XSet,seq1(typeset),Hyps2,_PT) | |
| 347 | ; check_is_subset(XSet,seq(typeset),Hyps2,_PT)). | |
| 348 | % check if something is an interval | |
| 349 | is_interval(Expr,Hyps,A,B) :- simplify_expr_loop(Expr,Hyps,SE), is_interval_aux(SE,A,B). | |
| 350 | is_interval_aux(interval(A,B),A,B). | |
| 351 | is_interval_aux(value(CS),A,B) :- nonvar(CS), CS= avl_set(AVL), avl_is_interval(AVL,A,B). | |
| 352 | ||
| 353 | is_set_of_sequences_type(seq1(_),_,seq1) :- !. | |
| 354 | is_set_of_sequences_type(seq(_),_,seq) :- !. | |
| 355 | is_set_of_sequences_type(iseq(_),_,seq) :- !. | |
| 356 | is_set_of_sequences_type(iseq1(_),_,seq) :- !. | |
| 357 | is_set_of_sequences_type(perm(A),Hyps,Type) :- !, | |
| 358 | (check_not_equal_empty_set(A,Hyps,_) -> Type=seq1 ; Type=seq). | |
| 359 | is_set_of_sequences_type(Func,Hyps,Type) :- % a total function 1..Up --> Range is a sequence | |
| 360 | get_exact_domain_of_func_or_rel_type(Func,Hyps,Dom,Hyps1), | |
| 361 | check_equal_pattern(Dom,interval(1,Up),Hyps1,Hyps2), | |
| 362 | % we could call check_equal for Low; relevant for :wd BV=16 & II=1 & BIdx = II..BV & s:BIdx --> BOOL & res=size(s) | |
| 363 | is_partial_function_type(Func,Hyps2,_), | |
| 364 | (number(Up), Up>0 % we could call check_leq | |
| 365 | -> Type=seq1 ; Type=seq). | |
| 366 | ||
| 367 | % a simple equality check | |
| 368 | check_equal_pattern(A,Target,Hyps,Hyps1) :- | |
| 369 | check_equal_h(A,Target,not_ground,[],Hyps,Hyps1). | |
| 370 | check_equal(A,Target,Hyps,Hyps1) :- | |
| 371 | check_equal_h(A,Target,ground,[],Hyps,Hyps1). | |
| 372 | ||
| 373 | % TargetGround=ground means Target is a ground, fully known expressions and not a pattern with variables | |
| 374 | check_equal_h(A,Target,_,_,Hyps,Hyps1) :- A=Target,!, Hyps1=Hyps. | |
| 375 | check_equal_h(union(A1,A2),union(B1,B2),TGr,History,Hyps,Hyps2) :- | |
| 376 | check_equal_h(A1,B1,TGr,History,Hyps,Hyps1),!, % TO DO: add other rules, e.g., check A1 and B2 | |
| 377 | check_equal_h(A2,B2,TGr,History,Hyps1,Hyps2). | |
| 378 | check_equal_h(couple(A1,A2),couple(B1,B2),TGr,History,Hyps,Hyps2) :- % TO DO: records, ... | |
| 379 | check_equal_h(A1,B1,TGr,History,Hyps,Hyps1),!, | |
| 380 | check_equal_h(A2,B2,TGr,History,Hyps1,Hyps2). | |
| 381 | check_equal_h(A,Target,TGr,History,Hyps,Hyps2) :- | |
| 382 | avl_fetch_equal_from_hyps(A,Hyps,A2,Hyps1), nonmember(A2,History), | |
| 383 | check_equal_h(A2,Target,TGr,[A|History],Hyps1,Hyps2). | |
| 384 | check_equal_h(A,Target,TGr,History,Hyps,Hyps2) :- Target = '$'(_), | |
| 385 | avl_fetch_equal_from_hyps(Target,Hyps,T2,Hyps1), nonmember(T2,History), | |
| 386 | check_equal_h(A,T2,TGr,[A|History],Hyps1,Hyps2). | |
| 387 | check_equal_h(A,Target,ground,_,Hyps,Hyps) :- | |
| 388 | avl_fetch_from_hyps(subset(A,Target),Hyps), | |
| 389 | avl_fetch_from_hyps(subset(Target,A),Hyps). | |
| 390 | check_equal_h(A,Empty,ground,_,Hyps,Hyps) :- is_empty_set_direct(Empty), !, check_empty_set(A,Hyps,_). | |
| 391 | check_equal_h(Empty,A,ground,_,Hyps,Hyps) :- is_empty_set_direct(Empty), !, check_empty_set(A,Hyps,_). | |
| 392 | ||
| 393 | infer_sequence_type_of_expr(sequence_extension([_|_]),_,seq1). | |
| 394 | infer_sequence_type_of_expr(sorted_set_extension(SList),_,seq1) :- | |
| 395 | sorted_set_extension_is_seq(SList,1). | |
| 396 | infer_sequence_type_of_expr(set_extension(List),_,seq1) :- sort(List,SList), | |
| 397 | sorted_set_extension_is_seq(SList,1). | |
| 398 | infer_sequence_type_of_expr(insert_tail(_,_),_,seq1). | |
| 399 | % we do not need to check Seq is a sequence; this will be checked in its own PO, ditto for operators below | |
| 400 | infer_sequence_type_of_expr(insert_front(_,_),_,seq1). | |
| 401 | infer_sequence_type_of_expr(concat(A,B),Hyps,R) :- | |
| 402 | ( infer_sequence_type_of_expr(A,Hyps,seq1) -> R=seq1 | |
| 403 | ; infer_sequence_type_of_expr(B,Hyps,seq1) -> R=seq1 | |
| 404 | ; R=seq). | |
| 405 | infer_sequence_type_of_expr(restrict_front(_,_),_,seq). | |
| 406 | infer_sequence_type_of_expr(restrict_tail(_,_),_,seq). | |
| 407 | infer_sequence_type_of_expr(rev(A),Hyps,R) :- | |
| 408 | (infer_sequence_type_of_expr(A,Hyps,seq1) -> R=seq1 ; R=seq). | |
| 409 | infer_sequence_type_of_expr(front(_),_,seq). % we could call check_not_empty_set(front(A),Hyps) | |
| 410 | infer_sequence_type_of_expr(tail(_),_,seq). % ditto | |
| 411 | infer_sequence_type_of_expr(general_concat(_),_,seq). | |
| 412 | infer_sequence_type_of_expr(value(avl_set(SeqAVL)),_,seq1) :- !, SeqAVL \= empty, | |
| 413 | safe_is_avl_sequence(SeqAVL). | |
| 414 | infer_sequence_type_of_expr(if_then_else(Pred,A,B),Hyps,Type) :- !, | |
| 415 | push_and_rename_normalized_hyp(Pred,Hyps,Hyps1), | |
| 416 | (hyps_inconsistent(Hyps1) | |
| 417 | -> push_and_rename_normalized_hyp(negation(Pred),Hyps,Hyps2), | |
| 418 | infer_sequence_type_of_expr(B,Hyps2,Type) | |
| 419 | ; infer_sequence_type_of_expr(A,Hyps1,S1), | |
| 420 | push_and_rename_normalized_hyp(negation(Pred),Hyps,Hyps2), | |
| 421 | (hyps_inconsistent(Hyps2) -> Type=S1 | |
| 422 | ; infer_sequence_type_of_expr(B,Hyps2,S2), lub_seq(S1,S2,Type)) | |
| 423 | ). | |
| 424 | infer_sequence_type_of_expr(external_function_call(Name,Args),Hyps,R) :- | |
| 425 | external_function_returns_sequence_type(Name,Args,Hyps,R,_). | |
| 426 | infer_sequence_type_of_expr(S,_,seq) :- is_empty_set_direct(S). | |
| 427 | infer_sequence_type_of_expr(Expr,Hyps,R) :- | |
| 428 | is_lambda_function_with_domain(Expr,Domain), | |
| 429 | Domain = interval(1,N), | |
| 430 | (check_leq(1,N,Hyps) -> R = seq1 ; R=seq). | |
| 431 | % TO DO: rule for composition | |
| 432 | ||
| 433 | lub_seq(seq1,seq1,seq1). | |
| 434 | lub_seq(seq1,seq,seq). | |
| 435 | lub_seq(seq,seq1,seq). | |
| 436 | lub_seq(seq,seq,seq). | |
| 437 | ||
| 438 | external_function_returns_sequence_type('STRING_CHARS',[Arg],Hyps,Type,FullType) :- !, | |
| 439 | (check_not_equal(Arg,string(''),Hyps) -> Type=seq1, FullType=seq1(string) ; Type=seq, FullType=seq(string)). | |
| 440 | external_function_returns_sequence_type('STRING_CODES',[Arg],Hyps,Type,FullType) :- !, | |
| 441 | (check_not_equal(Arg,string(''),Hyps) -> Type=seq1, FullType=seq1(integer) ; Type=seq, FullType=seq(integer)). | |
| 442 | external_function_returns_sequence_type(Name,_Args,_Hyps,Type,FullType) :- | |
| 443 | external_function_returns_sequence_type(Name,Type,FullType). | |
| 444 | ||
| 445 | :- use_module(probsrc(external_functions), [external_fun_type/3, performs_io/1]). | |
| 446 | % external functions which return sequences | |
| 447 | external_function_returns_sequence_type('STRING_SPLIT',Type,FullType) :- !, Type=seq1, FullType=seq1(string). | |
| 448 | external_function_returns_sequence_type(Name,seq,seq(Type)) :- external_fun_type(Name,_,List), | |
| 449 | last(List,ReturnType), nonvar(ReturnType), ReturnType=seq(RType), | |
| 450 | (ground(RType) -> Type = ReturnType ; Type=typeset). % 'REGEX_SEARCH_ALL', 'REGEX_ISEARCH_ALL', ... | |
| 451 | % TODO: use hyps, e.g., for STRING_CHARS(X) we have type seq1 if X/="" | |
| 452 | ||
| 453 | % check if a sorted set extension represent a proper sequence | |
| 454 | sorted_set_extension_is_seq([],_). | |
| 455 | sorted_set_extension_is_seq([couple(Nr,_)|T],Nr) :- N1 is Nr+1, sorted_set_extension_is_seq(T,N1). | |
| 456 | ||
| 457 | % -------- | |
| 458 | % DOMAIN | |
| 459 | ||
| 460 | % compute exact domain | |
| 461 | % currently there can be multiple solutions for $(_) case below; first one is usually more precise | |
| 462 | %compute_exact_domain(Value,Hyps2,Res) :- debug:print_quoted_with_max_depth(compute_exact_domain(Value,Hyps2,Res),4),nl,fail. | |
| 463 | ||
| 464 | ||
| 465 | compute_exact_domain(assertion_expression(_,_,Func),Hyps,Res,Hyps2) :- !, | |
| 466 | compute_exact_domain(Func,Hyps,Res,Hyps2). | |
| 467 | compute_exact_domain(closure(Func),Hyps,Res,Hyps2) :- !, % this is closure1 | |
| 468 | compute_exact_domain(Func,Hyps,Res,Hyps2). | |
| 469 | compute_exact_domain(reverse(Func),Hyps,Res,Hyps2) :- !, | |
| 470 | compute_exact_range(Func,Hyps,Res,Hyps2). | |
| 471 | compute_exact_domain(rev(Func),Hyps,Res,Hyps2) :- !, % reverse of a sequence; domain identical | |
| 472 | compute_exact_domain(Func,Hyps,Res,Hyps2). | |
| 473 | compute_exact_domain(identity(Domain),Hyps,Res,Hyps2) :- !, Hyps2=Hyps, Res=Domain. | |
| 474 | %compute_exact_domain(restrict_front(_Seq,N),Hyps,Res,Hyps2) :- !, | |
| 475 | % % WD Condition requires N : 0..size(Seq); | |
| 476 | % w/o it we loose the info that 1..N is a subset of dom(Seq); hence we comment this out, see test 2471 | |
| 477 | % Hyps2=Hyps, Res = interval(1,N). % TODO: similar rule for restrict_tail | |
| 478 | compute_exact_domain(Func,Hyps,Res,Hyps2) :- | |
| 479 | compute_exact_domain_direct(Func,Hyps,Res,Hyps2),!. % No recursive application of equal or hyp | |
| 480 | compute_exact_domain(Func,Hyps,Domain,Hyps2) :- | |
| 481 | avl_fetch_worthwhile_equal_from_hyps(Func,Hyps,Func2,Hyps1), | |
| 482 | compute_exact_domain(Func2,Hyps1,Domain,Hyps2). | |
| 483 | %compute_exact_domain(Expr,_,Domain,_) :- print(compute_exact_domain_failed(Expr,_,Domain)),nl,fail. | |
| 484 | ||
| 485 | ||
| 486 | compute_exact_domain_direct(Func,Hyps,Res,Hyps2) :- | |
| 487 | avl_fetch_mem_or_struct(Func,Hyps,Function,Hyps1), % look for Func : Res --> Range ; e.g. Func:perm(1..10) -> DomSet=1..10 | |
| 488 | % f : _ +-> ( Dom --> _ ) & x:Dom ==> x:dom(f(_)) | |
| 489 | % f : _ +-> ( Dom --> _ ) => dom(f(_)) = Dom | |
| 490 | get_exact_domain_of_func_or_rel_type(Function,Hyps1,Res,Hyps2),!. % is thus also minimal domain | |
| 491 | compute_exact_domain_direct(Func,Hyps,Res,Hyps3) :- Func = '$'(_), % Look for Func = Value definition | |
| 492 | avl_fetch_equal_from_hyps(Func,Hyps,Value,Hyps2), | |
| 493 | compute_exact_domain(Value,Hyps2,Res,Hyps3). | |
| 494 | compute_exact_domain_direct(value(CS),Hyps,value(Res),Hyps) :- !, nonvar(CS), | |
| 495 | domain_of_explicit_set_wf(CS,Res,no_wf_available). | |
| 496 | compute_exact_domain_direct(overwrite(F1,F2),Hyps,D12,Hyps2) :- !, % dom(F1 <+ F2) = dom(F1) \/ dom(F2) | |
| 497 | compute_exact_domain(F1,Hyps,D1,Hyps1), compute_exact_domain(F2,Hyps1,D2,Hyps2), | |
| 498 | construct_union(D1,D2,Hyps2,D12). | |
| 499 | compute_exact_domain_direct(domain_restriction(S,F),Hyps,intersection(S,D),Hyps2) :- !, % dom(S <| F) = S /\ dom(F) | |
| 500 | compute_exact_domain(F,Hyps,D,Hyps2). % SIMP_MULTI_DOM_DOMRES | |
| 501 | compute_exact_domain_direct(domain_subtraction(S,F),Hyps,set_subtraction(D,S),Hyps2) :- !, % dom(S <<| F) = dom(F) - S | |
| 502 | compute_exact_domain(F,Hyps,D,Hyps2). % SIMP_MULTI_DOM_DOMSUB | |
| 503 | compute_exact_domain_direct(direct_product(F,G),Hyps,intersection(DF,DG),Hyps2) :- !, % dom(F><G) = dom(F) /\ dom(G) | |
| 504 | compute_exact_domain(F,Hyps,DF,Hyps1), | |
| 505 | compute_exact_domain(G,Hyps1,DG,Hyps2). | |
| 506 | compute_exact_domain_direct(composition(F1,F2),Hyps,Domain,Hyps4) :- !, % dom((F1;F2)) = dom(F1) if ran(F1) <: dom(F2) | |
| 507 | compute_exact_domain(F1,Hyps,Domain,Hyps2), | |
| 508 | compute_exact_domain(F2,Hyps2,D2,Hyps3), % or_subset would also be ok | |
| 509 | (maximal_set(D2,Hyps3) -> Hyps4=Hyps3 | |
| 510 | ; get_range_or_superset(F1,Hyps3,R1,Hyps4), | |
| 511 | check_is_subset(R1,D2,Hyps4,_PT) | |
| 512 | ). | |
| 513 | compute_exact_domain_direct(union(F,G),Hyps,UnionDFDG,Hyps2) :- !, % dom(F \/ G) = dom(F) \/ dom(G) | |
| 514 | compute_exact_domain(F,Hyps,DF,Hyps1), | |
| 515 | compute_exact_domain(G,Hyps1,DG,Hyps2), | |
| 516 | construct_union(DF,DG,Hyps2,UnionDFDG). | |
| 517 | compute_exact_domain_direct(sorted_set_extension(List),Hyps,Res,Hyps2) :- !, | |
| 518 | compute_exact_domain_direct(set_extension(List),Hyps,Res,Hyps2). | |
| 519 | compute_exact_domain_direct(set_extension(List),Hyps,Res,Hyps) :- !, maplist(get_dom_el,List,Domain), | |
| 520 | construct_set_extension(Domain,Hyps,Res). | |
| 521 | compute_exact_domain_direct(Expr,Hyps,Domain,Hyps) :- is_lambda_function_with_domain(Expr,Domain),!. | |
| 522 | compute_exact_domain_direct(Func,Hyps,Domain,Hyps2) :- | |
| 523 | avl_fetch_equal_from_hyps(domain(Func),Hyps,Domain,Hyps2). | |
| 524 | ||
| 525 | % get domain element of a couple | |
| 526 | get_dom_el(couple(A,_),A). | |
| 527 | % get range element of a couple | |
| 528 | get_ran_el(couple(_,B),B). | |
| 529 | ||
| 530 | % construct union term with a few optimisations | |
| 531 | construct_union(empty_set,B,_Hyps,Res) :- !,Res=B. | |
| 532 | construct_union(set_extension(A),set_extension(B),Hyps,Res) :- !, | |
| 533 | append(A,B,AB), | |
| 534 | construct_set_extension(AB,Hyps,Res). | |
| 535 | construct_union(A,empty_set,_,Res) :- !,Res=A. | |
| 536 | construct_union(A,B,_,union(A,B)). | |
| 537 | ||
| 538 | % get maximal domain of a function (i.e., domain or superset thereof) | |
| 539 | :- if(environ(prob_safe_mode,true)). | |
| 540 | get_domain_or_superset(F,H,R,H2) :- nonvar(H2), | |
| 541 | add_internal_error('Instantiated hyps:',get_domain_or_superset(F,H,R,H2)),fail. | |
| 542 | :- endif. | |
| 543 | get_domain_or_superset(reverse(Func),Hyps,Res,Hyps2) :- !, | |
| 544 | get_range_or_superset(Func,Hyps,Res,Hyps2). | |
| 545 | get_domain_or_superset(domain(F),Hyps,Res,Hyps2) :- | |
| 546 | get_domain_or_superset(F,Hyps,DomF,Hyps1), | |
| 547 | get_domain_or_superset(DomF,Hyps1,Res,Hyps2). | |
| 548 | get_domain_or_superset(range(F),Hyps,Res,Hyps2) :- | |
| 549 | get_range_or_superset(F,Hyps,RanF,Hyps1), | |
| 550 | get_domain_or_superset(RanF,Hyps1,Res,Hyps2). | |
| 551 | get_domain_or_superset(comprehension_set(Ids,Pred),Hyps,comprehension_set(NewIds,Pred2),Hyps) :- | |
| 552 | append(NewIds,['$'(LastID)],Ids), % we project away last identifier | |
| 553 | NewIds \= [], % otherwise first and unique id is a pair | |
| 554 | conj_to_list(Pred,Preds,[]), | |
| 555 | exclude(uses_id(LastID),Preds,Preds2), % filter out all conjuncts using removed variable | |
| 556 | Preds2 \= [], % otherwise we simply have truth as body | |
| 557 | list_to_conj(Preds2,Pred2). | |
| 558 | get_domain_or_superset(Func,Hyps,Res,Hyps3) :- % sometimes rewrites terms to variables | |
| 559 | compute_exact_domain_direct(Func,Hyps,Res,Hyps2), | |
| 560 | rewrite_local_loop_check(Func,get_domain_or_superset,Res,Hyps2,Hyps3), | |
| 561 | !. | |
| 562 | get_domain_or_superset(domain_restriction(A,_),Hyps,Res,Hyps) :- Res=A. % in case compute_exact_domain_direct fails | |
| 563 | get_domain_or_superset(Func,Hyps,Res,Hyps1) :- | |
| 564 | function_restriction(Func,LargerFunc), | |
| 565 | get_domain_or_superset(LargerFunc,Hyps,Res,Hyps1). | |
| 566 | get_domain_or_superset(composition(F1,_),Hyps,Res,Hyps1) :- get_domain_or_superset(F1,Hyps,Res,Hyps1). | |
| 567 | get_domain_or_superset(direct_product(A,B),Hyps,Res,Hyps2) :- % dom(A >< B) = dom(A) /\ dom (B) | |
| 568 | (get_domain_or_superset(A,Hyps,Res,Hyps2) -> true | |
| 569 | ; get_domain_or_superset(B,Hyps,Res,Hyps2) -> true). | |
| 570 | get_domain_or_superset(tail(Seq),Hyps,Res,Hyps2) :- !, % dom(tail(S)) <: dom(S) | |
| 571 | get_domain_or_superset(Seq,Hyps,Res,Hyps2). | |
| 572 | get_domain_or_superset(front(Seq),Hyps,Res,Hyps2) :- !, % dom(front(S)) <: dom(S) | |
| 573 | get_domain_or_superset(Seq,Hyps,Res,Hyps2). | |
| 574 | get_domain_or_superset(restrict_front(Seq,K),Hyps,Res,Hyps2) :- !, % dom(S /|\ k) <: dom(S) | |
| 575 | (get_domain_or_superset(Seq,Hyps,Res,Hyps2) | |
| 576 | ; Res = interval(1,K), Hyps2=Hyps % WD Condition requires K : 0..size(Seq) | |
| 577 | ). | |
| 578 | get_domain_or_superset(restrict_tail(Seq,_),Hyps,Res,Hyps2) :- !, % dom(S \|/ k) <: dom(S) | |
| 579 | get_domain_or_superset(Seq,Hyps,Res,Hyps2). | |
| 580 | get_domain_or_superset(Func,Hyps,DomSet,Hyps2) :- simple_value(Func), | |
| 581 | avl_fetch_mem_or_struct(Func,Hyps,FunctionType,Hyps1), | |
| 582 | get_domain_or_superset_of_func_or_rel_type(FunctionType,Hyps1,DomSet,Hyps2), | |
| 583 | \+ maximal_set(DomSet,Hyps2). % inference useless | |
| 584 | get_domain_or_superset(Func,Hyps,Domain,Hyps2) :- | |
| 585 | avl_fetch_worthwhile_equal_from_hyps(Func,Hyps,Func2,Hyps1), | |
| 586 | get_domain_or_superset(Func2,Hyps1,Domain,Hyps2). | |
| 587 | get_domain_or_superset(Func,Hyps,DomSuperSet,Hyps2) :- | |
| 588 | avl_fetch_binop_from_hyps(domain(Func),subset,Hyps,DomSuperSet,Hyps2). | |
| 589 | ||
| 590 | uses_id(ID,Expr) :- occurs(Expr,ID). | |
| 591 | ||
| 592 | % get exact (thus also minimal) domain of a function type | |
| 593 | :- if(environ(prob_safe_mode,true)). | |
| 594 | get_exact_domain_of_func_or_rel_type(F,H,R,H2) :- | |
| 595 | nonvar(H2), add_internal_error('Instantiated hyps:',get_exact_domain_of_func_or_rel_type(F,H,R,H2)),fail. | |
| 596 | :- endif. | |
| 597 | get_exact_domain_of_func_or_rel_type(FunType,Hyps,A,Hyps) :- | |
| 598 | get_possible_domain_of_func_or_rel_type(FunType,Hyps,A,exact),!. | |
| 599 | get_exact_domain_of_func_or_rel_type(FunType,Hyps,Domain,Hyps2) :- | |
| 600 | avl_fetch_worthwhile_equal_from_hyps(FunType,Hyps,FunType2,Hyps1), % in case we have a definition like X = 1..n --> R | |
| 601 | get_exact_domain_of_func_or_rel_type(FunType2,Hyps1,Domain,Hyps2). | |
| 602 | get_exact_domain_of_func_or_rel_type(sorted_set_extension(F),Hyps,Domain,Hyps2) :- !, | |
| 603 | get_exact_domain_of_func_or_rel_type(set_extension(F),Hyps,Domain,Hyps2). | |
| 604 | get_exact_domain_of_func_or_rel_type(set_extension([Func|TF]),Hyps,Domain,Hyps2) :- | |
| 605 | compute_exact_domain(Func,Hyps,Domain,Hyps2), % now check that all other functions have the same domain | |
| 606 | (member(Func2,TF), \+ compute_exact_domain(Func2,Hyps2,Domain,_) -> fail | |
| 607 | ; true). | |
| 608 | ||
| 609 | get_possible_domain_of_func_or_rel_type(iseq(_),_,'NATURAL1',subset). | |
| 610 | get_possible_domain_of_func_or_rel_type(iseq1(_),_,'NATURAL1',subset). | |
| 611 | get_possible_domain_of_func_or_rel_type(partial_bijection(A,_),_,A,subset). | |
| 612 | get_possible_domain_of_func_or_rel_type(partial_function(A,_),_,A,subset). | |
| 613 | get_possible_domain_of_func_or_rel_type(partial_injection(A,_),_,A,subset). | |
| 614 | get_possible_domain_of_func_or_rel_type(partial_surjection(A,_),_,A,subset). | |
| 615 | get_possible_domain_of_func_or_rel_type(perm(A),Hyps,Domain,Type) :- | |
| 616 | (compute_card_of_set(A,Hyps,CardA,_) % we could do check_finite and use card(A) instead of CardA | |
| 617 | -> Domain = interval(1,CardA), Type=exact | |
| 618 | ; check_finite(A,Hyps,_) -> Domain = interval(1,card(A)), Type=exact | |
| 619 | ; %print(could_not_compute_card_for_perm(A)),nl, | |
| 620 | Domain = 'NATURAL1', Type=subset | |
| 621 | ). | |
| 622 | get_possible_domain_of_func_or_rel_type(relations(A,_),_,A,subset). | |
| 623 | get_possible_domain_of_func_or_rel_type(pow_subset(cartesian_product(A,_)),_,A,subset). | |
| 624 | get_possible_domain_of_func_or_rel_type(pow1_subset(cartesian_product(A,_)),_,A,subset). | |
| 625 | get_possible_domain_of_func_or_rel_type(fin_subset(cartesian_product(A,_)),_,A,subset). | |
| 626 | get_possible_domain_of_func_or_rel_type(fin1_subset(cartesian_product(A,_)),_,A,subset). | |
| 627 | get_possible_domain_of_func_or_rel_type(seq(_),_,'NATURAL1',subset). | |
| 628 | get_possible_domain_of_func_or_rel_type(seq1(_),_,'NATURAL1',subset). | |
| 629 | get_possible_domain_of_func_or_rel_type(surjection_relation(A,_),_,A,subset). | |
| 630 | get_possible_domain_of_func_or_rel_type(total_bijection(A,_),_,A,exact). | |
| 631 | get_possible_domain_of_func_or_rel_type(total_function(A,_),_,A,exact). | |
| 632 | get_possible_domain_of_func_or_rel_type(total_injection(A,_),_,A,exact). | |
| 633 | get_possible_domain_of_func_or_rel_type(total_relation(A,_),_,A,exact). | |
| 634 | get_possible_domain_of_func_or_rel_type(total_surjection_relation(A,_),_,A,exact). | |
| 635 | get_possible_domain_of_func_or_rel_type(total_surjection(A,_),_,A,exact). | |
| 636 | ||
| 637 | ||
| 638 | % variation of get_possible_domain_of_func_or_rel_type, which uses Hyps and can deal with set_extensions | |
| 639 | :- if(environ(prob_safe_mode,true)). | |
| 640 | get_domain_or_superset_of_func_or_rel_type(F,H,R,H2) :- nonvar(H2), | |
| 641 | add_internal_error('Instantiated hyps:',get_domain_or_superset_of_func_or_rel_type(F,H,R,H2)),fail. | |
| 642 | :- endif. | |
| 643 | get_domain_or_superset_of_func_or_rel_type(sorted_set_extension(List),Hyps,Dom,Hyps2) :- !, | |
| 644 | get_domain_or_superset_of_func_or_rel_type(set_extension(List),Hyps,Dom,Hyps2). | |
| 645 | get_domain_or_superset_of_func_or_rel_type(set_extension(List),Hyps,Dom,Hyps2) :- !, | |
| 646 | % if we have f: {f1,f2,...} => dom(f) <: dom(f1) \/ dom(f2) \/ ... | |
| 647 | merge_possible_domains_of_list(List,Hyps,empty_set,Dom,Hyps2). | |
| 648 | get_domain_or_superset_of_func_or_rel_type(Func,Hyps,Res,Hyps) :- | |
| 649 | get_possible_domain_of_func_or_rel_type(Func,Hyps,D,_),!,Res=D. | |
| 650 | ||
| 651 | % merge domains of a list of possible functions | |
| 652 | merge_possible_domains_of_list([],Hyps,Acc,Acc,Hyps). | |
| 653 | merge_possible_domains_of_list([H|T],Hyps,Acc,Res,Hyps2) :- | |
| 654 | get_domain_or_superset(H,Hyps,Domain,Hyps1),!, | |
| 655 | construct_union(Acc,Domain,Hyps1,Acc1), | |
| 656 | merge_possible_domains_of_list(T,Hyps1,Acc1,Res,Hyps2). | |
| 657 | ||
| 658 | % RANGE | |
| 659 | % ----- | |
| 660 | ||
| 661 | % compute range or subset thereof | |
| 662 | ||
| 663 | compute_exact_range(assertion_expression(_,_,Func),Hyps,Res,Hyps2) :- !, | |
| 664 | compute_exact_range(Func,Hyps,Res,Hyps2). | |
| 665 | compute_exact_range(closure(Func),Hyps,Res,Hyps2) :- !, % this is closure1 | |
| 666 | compute_exact_range(Func,Hyps,Res,Hyps2). | |
| 667 | compute_exact_range(reverse(Func),Hyps,Res,Hyps2) :- | |
| 668 | compute_exact_domain(Func,Hyps,Res,Hyps2). | |
| 669 | compute_exact_range(rev(Func),Hyps,Res,Hyps2) :- % reverse of a sequence: same range | |
| 670 | compute_exact_range(Func,Hyps,Res,Hyps2). | |
| 671 | compute_exact_range(identity(Domain),Hyps,Res,Hyps2) :- !, Hyps2=Hyps, Res=Domain. | |
| 672 | compute_exact_range(Func,Hyps,Res,Hyps2) :- | |
| 673 | compute_exact_range_direct(Func,Hyps,Res,Hyps2),!. % No recursive application of equal or hyp | |
| 674 | compute_exact_range(Func,Hyps,Res,Hyps2) :- Func = '$'(_), | |
| 675 | avl_fetch_mem_or_struct(Func,Hyps,FunctionType,Hyps2), % Func : _ --> Res | |
| 676 | get_exact_range_of_func_type_direct(FunctionType,Res). | |
| 677 | compute_exact_range(Func,Hyps,Range,Hyps2) :- | |
| 678 | avl_fetch_worthwhile_equal_from_hyps(Func,Hyps,Func2,Hyps1), | |
| 679 | compute_exact_range(Func2,Hyps1,Range,Hyps2). | |
| 680 | %compute_exact_range(Expr,H,Domain) :- nl,portray_hyps(H),nl,print(compute_range_failed(Expr,_,Domain)),nl,fail. | |
| 681 | % TO DO: rule for composition (exact case) | |
| 682 | ||
| 683 | ||
| 684 | compute_exact_range_direct(S,Hyps,empty_set,Hyps) :- is_empty_set_direct(S),!. | |
| 685 | compute_exact_range_direct(function(Func2,_),Hyps,Res,Hyps2) :- | |
| 686 | % f : _ +-> ( _ --> Ran ) & x:Ran ==> x:ran(f(_)) | |
| 687 | % f : _ +-> ( _ -->> Ran ) => ran(f(_)) = Ran | |
| 688 | get_range_or_superset(Func2,Hyps,Range,Hyps2), | |
| 689 | get_exact_range_of_func_type_direct(Range,Res). % is thus also minimal domain | |
| 690 | compute_exact_range_direct(value(CS),Hyps,value(Res),Hyps) :- !, nonvar(CS), % TO DO: maybe only if small enough | |
| 691 | range_of_explicit_set_wf(CS,Res,no_wf_available). | |
| 692 | compute_exact_range_direct(sequence_extension(L),Hyps,Res,Hyps) :- !, | |
| 693 | construct_set_extension(L,Hyps,Res). | |
| 694 | compute_exact_range_direct(union(F,G),Hyps,UnionRFRG,Hyps2) :- !, % ran(F \/ G) = ran(F) \/ ran(G) | |
| 695 | compute_exact_range(F,Hyps,RF,Hyps1), | |
| 696 | compute_exact_range(G,Hyps1,RG,Hyps2), | |
| 697 | construct_union(RF,RG,Hyps2,UnionRFRG). | |
| 698 | compute_exact_range_direct(sorted_set_extension(List),Hyps,Res,Hyps2) :- !, | |
| 699 | compute_exact_range_direct(set_extension(List),Hyps,Res,Hyps2). | |
| 700 | compute_exact_range_direct(set_extension(List),Hyps,Res,Hyps) :- !, maplist(get_ran_el,List,Domain), | |
| 701 | construct_set_extension(Domain,Hyps,Res). | |
| 702 | compute_exact_range_direct(Func,Hyps,Range,Hyps2) :- | |
| 703 | avl_fetch_equal_from_hyps(range(Func),Hyps,Range,Hyps2). | |
| 704 | ||
| 705 | % get maximal range of a function (i.e., range or superset thereof) | |
| 706 | :- if(environ(prob_safe_mode,true)). | |
| 707 | get_range_or_superset(P,H,R,H1) :- nonvar(H1), add_internal_error('Illegal hyps:',get_range_or_superset(P,H,R,H1)),fail. | |
| 708 | :- endif. | |
| 709 | get_range_or_superset(reverse(Func),Hyps,Res,Hyps2) :- !, | |
| 710 | get_domain_or_superset(Func,Hyps,Res,Hyps2). | |
| 711 | get_range_or_superset(domain(F),Hyps,Res,Hyps2) :- | |
| 712 | get_domain_or_superset(F,Hyps,DomF,Hyps1), | |
| 713 | get_range_or_superset(DomF,Hyps1,Res,Hyps2). | |
| 714 | get_range_or_superset(range(F),Hyps,Res,Hyps2) :- | |
| 715 | get_range_or_superset(F,Hyps,RanF,Hyps1), | |
| 716 | get_range_or_superset(RanF,Hyps1,Res,Hyps2). | |
| 717 | get_range_or_superset(Func,Hyps,Res,Hyps3) :- | |
| 718 | compute_exact_range_direct(Func,Hyps,Res,Hyps2), | |
| 719 | rewrite_local_loop_check(Func,get_range_or_superset,Res,Hyps2,Hyps3), | |
| 720 | !. % can be a loop dom(f) = ran(g) | |
| 721 | get_range_or_superset(function(Func2,_),Hyps,Res,Hyps2) :- | |
| 722 | % f2 : _ +-> ( _ --> Res ) ==> ran(f2(.)) <: Res | |
| 723 | get_range_or_superset(Func2,Hyps,Range,Hyps1), | |
| 724 | get_possible_range_of_func_or_rel_type(Range,Hyps1,Res,_,Hyps2). | |
| 725 | % TODO: try rewrite_function_application(Func,Args,Hyps,Result,Hyps2) ? | |
| 726 | get_range_or_superset(range_restriction(_,B),Hyps,Res,Hyps) :- Res=B. % in case compute_exact_range_direct fails | |
| 727 | get_range_or_superset(Func,Hyps,Res,Hyps1) :- | |
| 728 | function_restriction(Func,LargerFunc), | |
| 729 | get_range_or_superset(LargerFunc,Hyps,Res,Hyps1). | |
| 730 | get_range_or_superset(Func,Hyps,RangeSet,Hyps2) :- simple_value(Func), | |
| 731 | avl_fetch_mem_or_struct(Func,Hyps,FunctionType,Hyps1), | |
| 732 | get_possible_range_of_func_or_rel_type(FunctionType,Hyps1,RangeSet,_,Hyps2), | |
| 733 | \+ maximal_set(RangeSet,Hyps2). % inference useless. | |
| 734 | get_range_or_superset(tail(Seq),Hyps,Res,Hyps2) :- !, % ran(tail(S)) <: ran(S) | |
| 735 | get_range_or_superset(Seq,Hyps,Res,Hyps2). | |
| 736 | get_range_or_superset(front(Seq),Hyps,Res,Hyps2) :- !, % ran(front(S)) <: ran(S) | |
| 737 | get_range_or_superset(Seq,Hyps,Res,Hyps2). | |
| 738 | get_range_or_superset(restrict_front(Seq,_),Hyps,Res,Hyps2) :- !, % /|\ | |
| 739 | get_range_or_superset(Seq,Hyps,Res,Hyps2). | |
| 740 | get_range_or_superset(restrict_tail(Seq,_),Hyps,Res,Hyps2) :- !, | |
| 741 | get_range_or_superset(Seq,Hyps,Res,Hyps2). | |
| 742 | get_range_or_superset(concat(Seq1,Seq2),Hyps,Res12,Hyps2) :- !, % ran(S1^S2) = ran(S1) \/ ran(S2) | |
| 743 | get_range_or_superset(Seq1,Hyps,Res1,Hyps2), | |
| 744 | get_range_or_superset(Seq2,Hyps,Res2,Hyps2), | |
| 745 | construct_union(Res1,Res2,Hyps2,Res12). | |
| 746 | get_range_or_superset(composition(_,Func2),Hyps,Res2,Hyps2) :- !, % ran((F1;F2)) <: ran(F2) | |
| 747 | get_range_or_superset(Func2,Hyps,Res2,Hyps2). | |
| 748 | get_range_or_superset(Func,Hyps,Range,Hyps2) :- | |
| 749 | avl_fetch_worthwhile_equal_from_hyps(Func,Hyps,Func2,Hyps1), | |
| 750 | get_range_or_superset(Func2,Hyps1,Range,Hyps2). | |
| 751 | get_range_or_superset(Func,Hyps,RangeSuperSet,Hyps2) :- | |
| 752 | avl_fetch_binop_from_hyps(range(Func),subset,Hyps,RangeSuperSet,Hyps2). | |
| 753 | get_range_or_superset(comprehension_set(IDS,Body),Hyps,RangeSuperSet,Hyps2) :- | |
| 754 | get_lambda_args_and_body(IDS,Body,_,Expr,RestIDs,RestBodyList), | |
| 755 | add_new_hyp_any_vars(Hyps,RestIDs,Hyps0), % do not infer anything about lambda vars | |
| 756 | get_clash_renaming_subst(Hyps0,Renaming), | |
| 757 | l_push_normalized_hyp(RestBodyList,Renaming,Hyps0,Hyps1), | |
| 758 | (hyps_inconsistent(Hyps1) -> RangeSuperSet = empty_set, Hyps2=Hyps | |
| 759 | ; rename_norm_term(Expr,Renaming,RNExpr), | |
| 760 | try_get_set_of_possible_values(RNExpr,Hyps1,RangeSuperSet,Hyps2) | |
| 761 | ). | |
| 762 | % get_range_or_superset(Func,_,_,_) :- print(get_range_or_superset_failed(Func)),nl,fail. | |
| 763 | % to do: more sequence operations: insert_front, insert_tail | |
| 764 | ||
| 765 | l_push_normalized_hyp([],_,Hyp,Hyp). | |
| 766 | l_push_normalized_hyp([H|T],Renaming,Hyp0,Hyp2) :- | |
| 767 | rename_norm_term(H,Renaming,RenamedH), | |
| 768 | push_normalized_hyp(RenamedH,Hyp0,Hyp1), | |
| 769 | l_push_normalized_hyp(T,Renaming,Hyp1,Hyp2). | |
| 770 | ||
| 771 | % get exact range without equality rewrites | |
| 772 | get_exact_range_of_func_type_direct(Func,R) :- | |
| 773 | get_possible_range_of_func_or_rel_type_direct(Func,R,exact). | |
| 774 | % TO DO: maybe do same treatment for set_extension as in get_exact_domain_of_func_or_rel_type | |
| 775 | ||
| 776 | % get possible range with equality rewrites | |
| 777 | get_possible_range_of_func_or_rel_type(Func,Hyps,Range,ResType,Hyps2) :- | |
| 778 | get_possible_range_of_func_or_rel_type_direct(Func,Range,Type),!, ResType=Type,Hyps2=Hyps. | |
| 779 | get_possible_range_of_func_or_rel_type(Func,Hyps,Range,ResType,Hyps2) :- | |
| 780 | avl_fetch_worthwhile_equal_from_hyps(Func,Hyps,Func2,Hyps1), | |
| 781 | get_possible_range_of_func_or_rel_type(Func2,Hyps1,Range,ResType,Hyps2). | |
| 782 | ||
| 783 | % get possible range without equality rewrites | |
| 784 | get_possible_range_of_func_or_rel_type_direct(total_function(_,B),B,subset). | |
| 785 | get_possible_range_of_func_or_rel_type_direct(total_injection(_,B),B,subset). | |
| 786 | get_possible_range_of_func_or_rel_type_direct(total_surjection(_,B),B,exact). | |
| 787 | get_possible_range_of_func_or_rel_type_direct(total_bijection(_,B),B,exact). | |
| 788 | get_possible_range_of_func_or_rel_type_direct(total_relation(_,B),B,subset). | |
| 789 | get_possible_range_of_func_or_rel_type_direct(total_surjection_relation(_,B),B,exact). | |
| 790 | get_possible_range_of_func_or_rel_type_direct(partial_function(_,B),B,subset). | |
| 791 | get_possible_range_of_func_or_rel_type_direct(partial_injection(_,B),B,subset). | |
| 792 | get_possible_range_of_func_or_rel_type_direct(partial_surjection(_,B),B,exact). | |
| 793 | get_possible_range_of_func_or_rel_type_direct(partial_bijection(_,B),B,exact). | |
| 794 | get_possible_range_of_func_or_rel_type_direct(perm(B),B,exact). | |
| 795 | get_possible_range_of_func_or_rel_type_direct(iseq(B),B,subset). | |
| 796 | get_possible_range_of_func_or_rel_type_direct(iseq1(B),B,subset). | |
| 797 | get_possible_range_of_func_or_rel_type_direct(seq(B),B,subset). | |
| 798 | get_possible_range_of_func_or_rel_type_direct(seq1(B),B,subset). | |
| 799 | get_possible_range_of_func_or_rel_type_direct(relations(_,B),B,subset). | |
| 800 | get_possible_range_of_func_or_rel_type_direct(surjection_relation(_,B),B,exact). | |
| 801 | get_possible_range_of_func_or_rel_type_direct(pow_subset(cartesian_product(_,B)),B,subset). | |
| 802 | get_possible_range_of_func_or_rel_type_direct(pow1_subset(cartesian_product(_,B)),B,subset). | |
| 803 | get_possible_range_of_func_or_rel_type_direct(fin_subset(cartesian_product(_,B)),B,subset). | |
| 804 | get_possible_range_of_func_or_rel_type_direct(fin1_subset(cartesian_product(_,B)),B,subset). | |
| 805 | ||
| 806 | ||
| 807 | % EXACT REWRITING/SIMPLIFICATION RULES | |
| 808 | ||
| 809 | % simplifier, useful rules independent of context | |
| 810 | simplify_expr(A,Hyps,Res) :- | |
| 811 | simplify_expr(A,Hyps,1,Res). % no repeated applications of rule | |
| 812 | simplify_expr_loop(A,Hyps,Res) :- | |
| 813 | simplify_expr(A,Hyps,3,Res). % which value to use here? | |
| 814 | simplify_expr(A,Hyps,MaxLoop,Res) :- | |
| 815 | rewrite_set_expression_exact(A,Hyps,A2,Hyps2),!, | |
| 816 | simplify_iter(A2,Hyps2,MaxLoop,Res). | |
| 817 | simplify_expr(A,Hyps,MaxLoop,Res) :- | |
| 818 | rewrite_integer(A,Hyps,A2,Hyps2),!, | |
| 819 | simplify_iter(A2,Hyps2,MaxLoop,Res). | |
| 820 | simplify_expr(record_field(rec(Fields),Field),Hyps,MaxLoop,SExpr) :- | |
| 821 | member(field(Field,Expr),Fields),!, | |
| 822 | simplify_expr(Expr,Hyps,MaxLoop,SExpr). | |
| 823 | simplify_expr(domain(A),Hyps,MaxLoop,Res) :- | |
| 824 | simplify_domain(A,SA),!,simplify_expr(SA,Hyps,MaxLoop,Res). | |
| 825 | simplify_expr(range(A),Hyps,MaxLoop,Res) :- | |
| 826 | simplify_range(A,SA),!,simplify_expr(SA,Hyps,MaxLoop,Res). | |
| 827 | simplify_expr(E,_,_,E). | |
| 828 | ||
| 829 | simplify_iter(A,Hyps,MaxLoop,Res) :- MaxLoop > 1,!, | |
| 830 | M1 is MaxLoop-1, simplify_expr(A,Hyps,M1,Res). | |
| 831 | simplify_iter(A,_,_,A). | |
| 832 | ||
| 833 | simplify_domain(reverse(A),range(A)). | |
| 834 | simplify_domain(closure(A),domain(A)). % rx : A <-> B <=> closure1(rx) : A <-> B | |
| 835 | simplify_range(reverse(A),domain(A)). | |
| 836 | simplify_range(closure(A),range(A)). % rx : A <-> B <=> closure1(rx) : A <-> B | |
| 837 | ||
| 838 | get_lambda_args_and_body(IDS,Body,LambdaID,LambdaExpr,RestArgs,RestBodyList) :- | |
| 839 | LambdaID='$'(Lambda), | |
| 840 | append(RestArgs,[LambdaID],IDS), % TO DO: pass lambda info from typed unnormalized expression! | |
| 841 | conj_to_list(Body,BodyList,[]), | |
| 842 | select(equal(A,B),BodyList,RestBodyList), | |
| 843 | ( A=LambdaID, not_occurs(B,Lambda), LambdaExpr=B | |
| 844 | ; B=LambdaID, not_occurs(A,Lambda), LambdaExpr=A | |
| 845 | ). | |
| 846 | ||
| 847 | % just check if something is a lambda function or similar, without computing exact domain | |
| 848 | is_lambda_function(comprehension_set(IDS,Body)) :- !, | |
| 849 | get_lambda_args_and_body(IDS,Body,_,_,_,_). | |
| 850 | is_lambda_function(Expr) :- is_lambda_function_with_domain(Expr,_). | |
| 851 | ||
| 852 | % determine if something is a lambda function and determine exact domain: | |
| 853 | is_lambda_function_with_domain(comprehension_set(IDS,Body),Set) :- | |
| 854 | get_lambda_args_and_body(IDS,Body,_,_,Args,RestBodyList), | |
| 855 | get_argument_types(Args,Args,RestBodyList,ArgTypes), | |
| 856 | create_cartesian_product(ArgTypes,Set). | |
| 857 | is_lambda_function_with_domain(cartesian_product(Domain,Set),Domain) :- | |
| 858 | singleton_set(Set,_). | |
| 859 | is_lambda_function_with_domain(set_extension([couple(El,_)]),set_extension([El])). | |
| 860 | is_lambda_function_with_domain(Set,singleton_set([El])) :- singleton_set(Set,couple(El,_)). % TO DO: longer lists and check no multiple domain elements | |
| 861 | is_lambda_function_with_domain(sequence_extension(List),interval(1,Len)) :- length(List,Len). | |
| 862 | % we could treat domain_restriction, domain_subtraction here | |
| 863 | ||
| 864 | singleton_set(set_extension([El]),El). | |
| 865 | singleton_set(sorted_set_extension([El]),El). | |
| 866 | ||
| 867 | conj_to_list(conjunct(A,B)) --> !, conj_to_list(A),conj_to_list(B). | |
| 868 | conj_to_list(X) --> [X]. | |
| 869 | ||
| 870 | list_to_conj([],truth). | |
| 871 | list_to_conj([X],Res) :- !, Res=X. | |
| 872 | list_to_conj([H|T],conjunct(H,R)) :- list_to_conj(T,R). | |
| 873 | ||
| 874 | :- use_module(probsrc(tools),[map_split_list/4]). | |
| 875 | % we support Arg:Set and we support an argument not appearing at all (equivalent to Arg:typeset) | |
| 876 | get_argument_types([],_,[],[]). % no other conjuncts remain in body | |
| 877 | get_argument_types(['$'(ID1)|T],AllArgs,BodyList,[Set1|TS]) :- | |
| 878 | map_split_list(typing_predicate_for(ID1,AllArgs),BodyList,TypingSetList,RestBody), | |
| 879 | create_intersection(TypingSetList,Set1), | |
| 880 | get_argument_types(T,AllArgs,RestBody,TS). | |
| 881 | ||
| 882 | % check if we have a typing predicate for a given identifier | |
| 883 | typing_predicate_for(ID1,AllArgs,member('$'(ID1),Set1),Set1) :- l_not_occurs(Set1,AllArgs). | |
| 884 | typing_predicate_for(ID1,AllArgs,subset('$'(ID1),SSet1),pow_subset(SSet1)) :- l_not_occurs(SSet1,AllArgs). | |
| 885 | ||
| 886 | % check if any argument appears in expression; if so we have a link between arguments and no proper type | |
| 887 | l_not_occurs(Expr,AllArgs) :- member('$'(ID),AllArgs), occurs(Expr,ID),!,fail. | |
| 888 | l_not_occurs(_,_). | |
| 889 | ||
| 890 | create_intersection([],typeset). % no constraints on identifier: use typeset | |
| 891 | create_intersection([A],Res) :- !, Res=A. | |
| 892 | create_intersection([A|T],intersection(A,Rest)) :- create_intersection(T,Rest). | |
| 893 | ||
| 894 | create_cartesian_product([Type],Res) :- !, Res=Type. | |
| 895 | create_cartesian_product([Type|T],Res) :- create_cartesian_product3(T,Type,Res). | |
| 896 | ||
| 897 | create_cartesian_product3([],Res,Res). | |
| 898 | create_cartesian_product3([Type|T],Acc,Res) :- | |
| 899 | create_cartesian_product3(T,cartesian_product(Acc,Type),Res). | |
| 900 | % Note: dom(%(x,y,z).(x:BOOL & y:1..2 & z:BOOL|1)) = (BOOL*(1..2))*BOOL | |
| 901 | ||
| 902 | % ------------------------ | |
| 903 | ||
| 904 | % Partial Function Check: | |
| 905 | ||
| 906 | % check if Func : Domain +-> Range | |
| 907 | check_is_partial_function_with_type(Func,_,_,Hyps,empty_set(PT)) :- check_equal_empty_set(Func,Hyps,PT),!. | |
| 908 | check_is_partial_function_with_type(Func,Domain,Range,Hyps,pfun(PTD,PTR)) :- | |
| 909 | check_is_partial_function(Func,Hyps),!, | |
| 910 | (maximal_set(Domain,Hyps) -> PTD=maximal_domain ; check_is_subset(domain(Func),Domain,Hyps,PTD)),!, | |
| 911 | (maximal_set(Range,Hyps) -> PTR=maximal_range ; check_is_subset(range(Func),Range,Hyps,PTR)). | |
| 912 | ||
| 913 | % various way to make a function smaller, related to subset | |
| 914 | function_restriction(domain_subtraction(_,F),F). | |
| 915 | function_restriction(domain_restriction(_,F),F). | |
| 916 | function_restriction(range_subtraction(F,_),F). | |
| 917 | function_restriction(range_restriction(F,_),F). | |
| 918 | function_restriction(set_subtraction(F,_),F). | |
| 919 | ||
| 920 | % check if Func : DomTYPE +-> RanTYPE | |
| 921 | % check if we can deduce from the Hypotheses that something is a partial function | |
| 922 | check_is_partial_function(Func,Hyps) :- | |
| 923 | avl_fetch_mem_or_struct(Func,Hyps,Function,Hyps1), | |
| 924 | % also deals with function(_) f : _ +-> ( _ +-> _ ) => f(_) : _ +-> _ | |
| 925 | is_partial_function_type(Function,Hyps1,_),!. | |
| 926 | check_is_partial_function(reverse(Func),Hyps) :- | |
| 927 | check_is_injective(Func,Hyps),!. | |
| 928 | check_is_partial_function(value(avl_set(AVL)),_) :- !, | |
| 929 | nonvar(AVL), | |
| 930 | is_avl_partial_function(AVL). | |
| 931 | check_is_partial_function(composition(F1,F2),Hyp) :- !, | |
| 932 | % composition of two partial functions is a partial function | |
| 933 | (check_is_partial_function(F1,Hyp) | |
| 934 | -> check_is_partial_function(F2,Hyp) | |
| 935 | ). | |
| 936 | check_is_partial_function(overwrite(F1,F2),Hyp) :- !, | |
| 937 | % overwrite of two partial functions is a partial function | |
| 938 | (check_is_partial_function(F1,Hyp) | |
| 939 | -> check_is_partial_function(F2,Hyp) | |
| 940 | ). | |
| 941 | check_is_partial_function(direct_product(F1,F2),Hyp) :- !, | |
| 942 | % direct_product of two partial functions is a partial function a:A+->B & b:A+->C => a><b : A+->(B*C) | |
| 943 | (check_is_partial_function(F1,Hyp) | |
| 944 | -> check_is_partial_function(F2,Hyp) | |
| 945 | ). | |
| 946 | check_is_partial_function(identity(_),_Hyp) :- !. | |
| 947 | check_is_partial_function(Func,Hyp) :- function_restriction(Func,LargerFunc), !, | |
| 948 | check_is_partial_function(LargerFunc,Hyp). | |
| 949 | check_is_partial_function(intersection(F1,F2),Hyp) :- !, | |
| 950 | (check_is_partial_function(F1,Hyp) -> true ; check_is_partial_function(F2,Hyp)). | |
| 951 | check_is_partial_function(sorted_set_extension(List),Hyp) :- !, | |
| 952 | check_set_extension_is_partial_function(List,Hyp). | |
| 953 | check_is_partial_function(set_extension(List),Hyp) :- !, | |
| 954 | check_set_extension_is_partial_function(List,Hyp). | |
| 955 | check_is_partial_function(Expr,_) :- | |
| 956 | is_lambda_function(Expr),!. % also treats cartesian_product and sequence_extension | |
| 957 | % check_is_partial_function(X,_Hyp) :- is_empty_set_direct(X),!. % covered by infer_sequence_type_of_expr below | |
| 958 | check_is_partial_function(Expr,Hyps) :- | |
| 959 | infer_sequence_type_of_expr(Expr,Hyps,_),!. % any sequence expression is a partial function; e.g. a <- b, front(.) | |
| 960 | check_is_partial_function(Func,Hyps) :- rewrite_set_expression_exact(Func,Hyps,NewFunc,Hyps2),!, | |
| 961 | check_is_partial_function(NewFunc,Hyps2). | |
| 962 | check_is_partial_function(union(F1,F2),Hyps) :- | |
| 963 | check_is_subset(F1,F2,Hyps,_),!, | |
| 964 | check_is_partial_function(F2,Hyps). | |
| 965 | check_is_partial_function(union(F1,F2),Hyps) :- | |
| 966 | check_is_subset(F2,F1,Hyps,_),!, | |
| 967 | check_is_partial_function(F1,Hyps). | |
| 968 | check_is_partial_function(union(F1,F2),Hyps) :- !, | |
| 969 | check_domain_disjoint(F1,F2,Hyps,Hyps2), % domain must be disjoint, not F1 and F2 | |
| 970 | check_is_partial_function(F1,Hyps2), | |
| 971 | check_is_partial_function(F2,Hyps2). | |
| 972 | check_is_partial_function(Func,Hyps) :- % f<:g & g: A +-> B => f : A +-> B | |
| 973 | (Op = equal ; Op = subset), | |
| 974 | avl_fetch_binop_from_hyps(Func,Op,Hyps,Func2,Hyps1), | |
| 975 | quick_not_occurs_check(Func,Func2), | |
| 976 | check_is_partial_function(Func2,Hyps1). | |
| 977 | ||
| 978 | check_domain_disjoint(F1,F2,Hyps,Hyps2) :- | |
| 979 | compute_exact_domain(F1,Hyps,DF1,Hyps2), | |
| 980 | % example: :prove f:BOOL +-> BOOL & x /: dom(f) => f \/ {x|->TRUE} : BOOL +-> BOOL | |
| 981 | is_set_extension(DF1,List1),!, | |
| 982 | l_check_not_member_of_set(List1,domain(F2),Hyps2). % we could try and compute domain(F2) first | |
| 983 | check_domain_disjoint(F2,F1,Hyps,Hyps2) :- | |
| 984 | compute_exact_domain(F1,Hyps,DF1,Hyps2), | |
| 985 | is_set_extension(DF1,List1),!, | |
| 986 | l_check_not_member_of_set(List1,domain(F2),Hyps2). | |
| 987 | check_domain_disjoint(F1,F2,Hyps,Hyps2) :- | |
| 988 | get_domain_or_superset(F1,Hyps,DomFunc1,Hyps1), | |
| 989 | get_domain_or_superset(F2,Hyps1,DomFunc2,Hyps2), | |
| 990 | check_disjoint(DomFunc1,DomFunc2,Hyps2). | |
| 991 | ||
| 992 | %check_is_partial_function(Func,_) :- print(check_is_partial_function_failed(Func)),nl,fail. | |
| 993 | ||
| 994 | % check if this is a partial function type or something defined to be equal to a function type | |
| 995 | :- if(environ(prob_safe_mode,true)). | |
| 996 | is_partial_function_type(P,H,H1) :- nonvar(H1), | |
| 997 | add_internal_error('Illegal hyps:',is_partial_function_type(P,H,H1)),fail. | |
| 998 | :- endif. | |
| 999 | is_partial_function_type(PF,Hyps,Hyps1) :- is_partial_function(PF,_,_),!,Hyps1=Hyps. | |
| 1000 | is_partial_function_type(range(Func),Hyps,Hyps2) :- | |
| 1001 | get_range_or_superset(Func,Hyps,RanFunc,Hyps1),!, | |
| 1002 | is_partial_function_type(RanFunc,Hyps1,Hyps2). | |
| 1003 | is_partial_function_type(domain(Func),Hyps,Hyps2) :- | |
| 1004 | get_domain_or_superset(Func,Hyps,DomFunc,Hyps1),!, | |
| 1005 | is_partial_function_type(DomFunc,Hyps1,Hyps2). | |
| 1006 | is_partial_function_type(sorted_set_extension(Funcs),Hyps,Hyps2) :- !, | |
| 1007 | is_partial_function_type(set_extension(Funcs),Hyps,Hyps2). | |
| 1008 | is_partial_function_type(set_extension(Funcs),Hyps,Hyps2) :- !, | |
| 1009 | (member(F,Funcs), \+ check_is_partial_function(F,Hyps) -> fail | |
| 1010 | ; Hyps2=Hyps). % all elements of Funcs are partial functions | |
| 1011 | is_partial_function_type(Func,Hyps,Hyps2) :- | |
| 1012 | get_superset(Func,Hyps,SuperSet,Hyps1),!, | |
| 1013 | is_partial_function_type(SuperSet,Hyps1,Hyps2). | |
| 1014 | is_partial_function_type(PF,Hyps,Hyps2) :- | |
| 1015 | avl_fetch_worthwhile_equal_from_hyps(PF,Hyps,PF2,Hyps1), % in case we have a definition like X = 1..n --> R | |
| 1016 | is_partial_function_type(PF2,Hyps1,Hyps2). | |
| 1017 | ||
| 1018 | % get worthwhile superset | |
| 1019 | get_superset(comprehension_set([ID],Body),Hyps,Set,Hyps) :- | |
| 1020 | get_parameter_superset_in_body(ID,[ID],Body,Set). | |
| 1021 | get_superset(set_subtraction(A,_),Hyps,A,Hyps). | |
| 1022 | get_superset(intersection(A,B),Hyps,R,Hyps) :- (R=A ; R=B). | |
| 1023 | ||
| 1024 | is_partial_function(total_function(A,B),A,B). | |
| 1025 | is_partial_function(partial_function(A,B),A,B). | |
| 1026 | is_partial_function(total_injection(A,B),A,B). | |
| 1027 | is_partial_function(partial_injection(A,B),A,B). | |
| 1028 | is_partial_function(total_surjection(A,B),A,B). | |
| 1029 | is_partial_function(partial_surjection(A,B),A,B). | |
| 1030 | is_partial_function(total_bijection(A,B),A,B). | |
| 1031 | is_partial_function(partial_bijection(A,B),A,B). | |
| 1032 | is_partial_function(perm(A),'NATURAL1',A). | |
| 1033 | is_partial_function(seq(B),'NATURAL1',B). | |
| 1034 | is_partial_function(seq1(B),'NATURAL1',B). | |
| 1035 | is_partial_function(iseq(B),'NATURAL1',B). | |
| 1036 | is_partial_function(iseq1(B),'NATURAL1',B). | |
| 1037 | ||
| 1038 | % if First = f(1,GS) -> we can check if function is total; we could store summary of set_extension in hyps | |
| 1039 | check_set_extension_is_partial_function([_],_) :- !. % one element set extension is a function | |
| 1040 | check_set_extension_is_partial_function(List,Hyps) :- | |
| 1041 | maplist(get_explicit_dom_value(Hyps),List,VList),!, | |
| 1042 | sort(VList,SList), | |
| 1043 | SList = [couple(First,_)|TS], | |
| 1044 | check_set_ext_pf(TS,First,Hyps). | |
| 1045 | check_set_extension_is_partial_function([couple(A,_),couple(B,_)],Hyps) :- | |
| 1046 | check_not_equal(A,B,Hyps). % TO DO: all_different for longer lists | |
| 1047 | ||
| 1048 | check_set_ext_pf([],_,_). | |
| 1049 | check_set_ext_pf([couple(Next,_)|TS],Last,Hyp) :- | |
| 1050 | Next \= Last, | |
| 1051 | check_set_ext_pf(TS,Next,Hyp). | |
| 1052 | ||
| 1053 | get_explicit_dom_value(Hyps,couple(Val,RanVal),couple(Val2,RanVal)) :- get_explicit_value(Val,Hyps,Val2). | |
| 1054 | ||
| 1055 | get_explicit_value(couple(A,B),Hyps,couple(A2,B2)) :- !, | |
| 1056 | get_explicit_value(A,Hyps,A2), get_explicit_value(B,Hyps,B2). | |
| 1057 | get_explicit_value(rec(Fields),Hyps,rec(SFields2)) :- !, | |
| 1058 | maplist(get_field_value(Hyps),Fields,Fields2), | |
| 1059 | sort(Fields2,SFields2). | |
| 1060 | get_explicit_value(Val,Hyps,R) :- is_explicit_value(Val,AVal,Hyps),!,R=AVal. | |
| 1061 | get_explicit_value('$'(ID),Hyps,Res) :- | |
| 1062 | avl_fetch_equal_from_hyps('$'(ID),Hyps,Val2,Hyps2), | |
| 1063 | is_explicit_value(Val2,Res,Hyps2). % should we allow recursion through multiple equations? | |
| 1064 | ||
| 1065 | % is value which can be compared using Prolog equality | |
| 1066 | % cf. avl_can_fetch | |
| 1067 | is_explicit_value(boolean_true,pred_true,_). | |
| 1068 | is_explicit_value(boolean_false,pred_false,_). | |
| 1069 | is_explicit_value(Nr,Nr,_) :- number(Nr). % integers and floats | |
| 1070 | is_explicit_value(integer(Nr),Nr,_) :- integer(Nr). % normally already replaced by norm_expr2 | |
| 1071 | is_explicit_value(string(Atom),Atom,_). | |
| 1072 | is_explicit_value(real(Atom),Res,_) :- atom(Atom), | |
| 1073 | construct_real(Atom,term(floating(Res))). % c.f. is_real/1 in kernel_reals | |
| 1074 | is_explicit_value(couple(A,B),(AV,BV),Hyp) :- is_explicit_value(A,AV,Hyp), is_explicit_value(B,BV,Hyp). | |
| 1075 | is_explicit_value('$'(ID),'$'(ID),Hyp) :- is_global_constant_id(ID,Hyp). | |
| 1076 | is_explicit_value(value(R),Nr,_) :- nonvar(R),R=int(Nr), integer(Nr). % TODO: more values, strings, reals, ... | |
| 1077 | ||
| 1078 | ||
| 1079 | get_field_value(Hyps,field(Name,Val),field(Name,Val2)) :- get_explicit_value(Val,Hyps,Val2). | |
| 1080 | ||
| 1081 | :- use_module(probsrc(b_global_sets), [lookup_global_constant/2]). | |
| 1082 | % enumerated set element name | |
| 1083 | is_global_constant_id(ID,Hyp) :- | |
| 1084 | lookup_global_constant(ID,_), | |
| 1085 | \+ is_hyp_var(ID,Hyp). % global enumerated set constant visible | |
| 1086 | ||
| 1087 | is_enumerated_set(ID,Hyp) :- | |
| 1088 | enumerated_set(ID), | |
| 1089 | \+ is_hyp_var(ID,Hyp). % global enumerated set constant visible | |
| 1090 | ||
| 1091 | % Disjoint check: | |
| 1092 | check_disjoint(A,B,Hyps) :- %print(disj(A,B)),nl, portray_hyps(Hyps),nl, | |
| 1093 | (check_disjoint_aux(A,B,Hyps) -> true ; check_disjoint_aux(B,A,Hyps)). | |
| 1094 | check_disjoint_aux(S,_,Hyps) :- check_equal_empty_set(S,Hyps,_),!. | |
| 1095 | check_disjoint_aux(A,B,Hyps) :- | |
| 1096 | avl_fetch_from_hyps(equal(intersection(A,B),empty_set),Hyps),!. | |
| 1097 | check_disjoint_aux(domain_subtraction(A,_),B,Hyps) :- !, % A <<| f /\ B = {} if dom(B) <: A | |
| 1098 | get_domain_or_superset(B,Hyps,DomB,Hyps2), | |
| 1099 | check_is_subset(DomB,A,Hyps2,_). | |
| 1100 | check_disjoint_aux(set_subtraction(AA,A),B,Hyps) :- !, | |
| 1101 | (check_is_subset(B,A,Hyps,_) -> true % x \ A /\ B = {} if B <: A | |
| 1102 | ; check_disjoint(AA,B,Hyps) -> true). % AA-A /\ B ={} if AA /\ B = {} | |
| 1103 | check_disjoint_aux(set_extension(As),B,Hyps) :- !, l_check_not_member_of_set(As,B,Hyps). | |
| 1104 | check_disjoint_aux(sorted_set_extension(As),B,Hyps) :- !, l_check_not_member_of_set(As,B,Hyps). | |
| 1105 | check_disjoint_aux(A,B,Hyps) :- | |
| 1106 | avl_fetch_worthwhile_equal_from_hyps(A,Hyps,A1,Hyps1), | |
| 1107 | check_disjoint(A1,B,Hyps1). | |
| 1108 | % TO DO: move union of set_extension here? | |
| 1109 | ||
| 1110 | l_check_not_member_of_set([],_,_). | |
| 1111 | l_check_not_member_of_set([El|T],Set,Hyps) :- | |
| 1112 | check_not_member_of_set(Set,El,Hyps,_PT), | |
| 1113 | l_check_not_member_of_set(T,Set,Hyps). | |
| 1114 | ||
| 1115 | % Injective check: | |
| 1116 | ||
| 1117 | check_is_injective(Func,Hyps) :- | |
| 1118 | get_type_from_hyps(Func,Hyps,Function,Hyps1), | |
| 1119 | %print(check_rev_fun(Func,Function)),nl, | |
| 1120 | is_injective_function_type(Function,Hyps1,_). | |
| 1121 | check_is_injective(value(avl_set(AVL)),_) :- !, | |
| 1122 | nonvar(AVL), invert_explicit_set(avl_set(AVL),Inv), | |
| 1123 | Inv=avl_set(AVL2), is_avl_partial_function(AVL2). | |
| 1124 | check_is_injective(identity(_),_). | |
| 1125 | check_is_injective(Set,_) :- singleton_set(Set,_). % TO DO: extend to more than singleton set_extension | |
| 1126 | check_is_injective(sequence_extension([_]),_). % TO DO: check all elements are different | |
| 1127 | check_is_injective(Func, Hyps) :- | |
| 1128 | avl_fetch_equal_from_hyps(Func,Hyps,Value,Hyps2), | |
| 1129 | %print(check_inj_value(Func,Value)),nl, | |
| 1130 | check_is_injective(Value,Hyps2). | |
| 1131 | ||
| 1132 | % check if this is a partial function type or something defined to be equal to a function type | |
| 1133 | is_injective_function_type(PF,Hyps,Hyps1) :- is_injective(PF),!,Hyps1=Hyps. | |
| 1134 | is_injective_function_type(PF,Hyps,Hyps2) :- | |
| 1135 | avl_fetch_worthwhile_equal_from_hyps(PF,Hyps,PF2,Hyps1), % in case we have a definition like X = 1..n --> R | |
| 1136 | is_injective_function_type(PF2,Hyps1,Hyps2). | |
| 1137 | ||
| 1138 | is_injective(total_injection(_,_)). | |
| 1139 | is_injective(partial_injection(_,_)). | |
| 1140 | is_injective(total_bijection(_,_)). | |
| 1141 | is_injective(partial_bijection(_,_)). | |
| 1142 | is_injective(iseq(_)). | |
| 1143 | is_injective(iseq1(_)). | |
| 1144 | ||
| 1145 | % A /<: B <=> A/<<: B & A /= B | |
| 1146 | ||
| 1147 | check_not_subset(Sub,Super,Hyps,not_subset_interval) :- % R..S /<: X..Y | |
| 1148 | is_interval(Sub,Hyps,R,S), | |
| 1149 | is_interval(Super,Hyps,X,Y),!, | |
| 1150 | check_not_subset_interval(R,S,X,Y,Hyps). | |
| 1151 | check_not_subset(A,B,Hyps,PT) :- | |
| 1152 | check_not_is_subset_strict(A,B,Hyps,PT),!, | |
| 1153 | check_not_equal(A,B,Hyps). | |
| 1154 | ||
| 1155 | check_not_subset_interval(R,S,X,Y,Hyps) :- | |
| 1156 | check_not_empty_interval(R,S,Hyps), !, % empty set is always a subset | |
| 1157 | (check_less(Y,S,Hyps) -> true % interval extends right beyond Y | |
| 1158 | ; check_less(R,X,Hyps) -> true % interval extends left beyond X | |
| 1159 | ). | |
| 1160 | ||
| 1161 | check_not_empty_interval(Low,Up,Hyps) :- check_leq(Low,Up,Hyps). | |
| 1162 | ||
| 1163 | % check_not_is_subset_strict(A,B,Hyps,PT) check if A is not a strict subset of B | |
| 1164 | % not really used for WD proofs at the moment; mainly as top-level goal in prove_po | |
| 1165 | % (now used for proving set_subtraction is not empty; test 2469) | |
| 1166 | % probably quite a few more rules necessary to make it useful | |
| 1167 | check_not_is_subset_strict(A,B,Hyps,hyp) :- | |
| 1168 | avl_fetch_from_hyps(not_subset_strict(A,B),Hyps),!. % hyp; currently not marked as useful by default! | |
| 1169 | check_not_is_subset_strict(A,B,Hyps,hyp2) :- | |
| 1170 | avl_fetch_from_hyps(not_subset(A,B),Hyps),!. % not(A <: B) => not (A<<:B) | |
| 1171 | check_not_is_subset_strict(A,B,Hyps,equal(PT)) :- | |
| 1172 | check_equal(A,B,Hyps,PT),!. % A=B => not (A<<:B) | |
| 1173 | check_not_is_subset_strict(_,B,Hyps,empty_set(PT)) :- % A /<<: {} | |
| 1174 | check_equal_empty_set(B,Hyps,PT). | |
| 1175 | check_not_is_subset_strict(Sub,Super,Hyps,not_subset_interval) :- % R..S /<: X..Y => R..S /<<: X..Y | |
| 1176 | is_interval(Sub,Hyps,R,S), | |
| 1177 | is_interval(Super,Hyps,X,Y),!, | |
| 1178 | check_not_subset_interval(R,S,X,Y,Hyps). | |
| 1179 | check_not_is_subset_strict(MAX,_,Hyps,maximal_set) :- % MAX /<<: B | |
| 1180 | maximal_set(MAX,Hyps),!. | |
| 1181 | check_not_is_subset_strict(A,B,Hyps,not_empty_singleton(PT)) :- % x <<: {A} <=> x={} | |
| 1182 | singleton_set(B,_),!, | |
| 1183 | check_not_equal_empty_set(A,Hyps,PT). | |
| 1184 | check_not_is_subset_strict(A,B,Hyps,infinite_sub(PT)) :- | |
| 1185 | infinite_integer_set(A,Hyps), % TODO: accept more infinite sets | |
| 1186 | check_finite(B,Hyps,PT),!. | |
| 1187 | check_not_is_subset_strict(A,B,Hyps,superset_eq1(PT)) :- | |
| 1188 | (Operator = equal ; Operator = superset), % A :> S2 & S2 /<<: B => A /<<: B | |
| 1189 | avl_fetch_binop_from_hyps(A,Operator,Hyps,S2,Hyps2), | |
| 1190 | rewrite_local_loop_check(A,check_not_is_subset_strict,S2,Hyps2,Hyps3), | |
| 1191 | check_not_is_subset_strict(S2,B,Hyps3,PT),!. | |
| 1192 | check_not_is_subset_strict(A,B,Hyps,subset_eq2(PT)) :- | |
| 1193 | (Operator = equal ; Operator = subset), % B <: S2 & A /<<: S2 => A /<<: B | |
| 1194 | avl_fetch_binop_from_hyps(B,Operator,Hyps,S2,Hyps2), | |
| 1195 | rewrite_local_loop_check(B,check_not_is_subset_strict,S2,Hyps2,Hyps3), | |
| 1196 | check_not_is_subset_strict(A,S2,Hyps3,PT),!. | |
| 1197 | %check_not_is_subset_strict(A,B,H,_) :- print(check_not_is_subset_strict_failed(A,B)),nl, portray_hyps(H),nl,fail. | |
| 1198 | ||
| 1199 | ||
| 1200 | check_is_subset_strict(A,B,Hyp,empty_singleton(PT)) :- % x <<: {A} <=> x={} | |
| 1201 | singleton_set(B,_),!, | |
| 1202 | check_equal_empty_set(A,Hyp,PT). | |
| 1203 | check_is_subset_strict(A,B,Hyp,PT) :- % A <<: B <=> A <: B & A /= B | |
| 1204 | check_is_subset(A,B,Hyp,PT),!, | |
| 1205 | check_not_equal(A,B,Hyp). | |
| 1206 | ||
| 1207 | % check if something is a subset of something else | |
| 1208 | check_is_subset(H,H,_,equal). | |
| 1209 | check_is_subset(A,B,Hyps,hyp) :- | |
| 1210 | avl_fetch_from_hyps(subset(A,B),Hyps),!. % hyp | |
| 1211 | check_is_subset(_,MAX,Hyps,maximal_set) :- maximal_set(MAX,Hyps),!. | |
| 1212 | check_is_subset(S,_,Hyps,empty_set(PT)) :- check_equal_empty_set(S,Hyps,PT),!. % {} <: B | |
| 1213 | check_is_subset(cartesian_product(A,B),cartesian_product(A2,B2),Hyps,cart(PTA,PTB)) :- !, | |
| 1214 | % A <: A2 & B <: B2 => (A*B) <: (A2*B2) | |
| 1215 | (check_is_subset(A,A2,Hyps,PTA) | |
| 1216 | -> check_is_subset(B,B2,Hyps,PTB)). | |
| 1217 | check_is_subset('NATURAL1','NATURAL',_,nat1_nat) :- !. | |
| 1218 | check_is_subset(interval(L,U),B,Hyps,interval(PT)) :- !, check_subset_interval(B,L,U,Hyps,PT). | |
| 1219 | check_is_subset(intersection(A,B),Super,Hyps,intersection(PT)) :- !, | |
| 1220 | ( check_is_subset(A,Super,Hyps,PT) -> true ; check_is_subset(B,Super,Hyps,PT)). | |
| 1221 | check_is_subset(union(A,B),Super,Hyps,union(PTA,PTB)) :- !, | |
| 1222 | ( check_is_subset(A,Super,Hyps,PTA) -> check_is_subset(B,Super,Hyps,PTB)). | |
| 1223 | check_is_subset(domain_subtraction(_,B),Super,Hyps,dom_sub(PT)) :- !,check_is_subset(B,Super,Hyps,PT). | |
| 1224 | check_is_subset(domain_restriction(_,B),Super,Hyps,dom_res(PT)) :- !,check_is_subset(B,Super,Hyps,PT). | |
| 1225 | check_is_subset(range_subtraction(A,_),Super,Hyps,ran_sub(PT)) :- !,check_is_subset(A,Super,Hyps,PT). | |
| 1226 | check_is_subset(range_restriction(A,_),Super,Hyps,ran_res(PT)) :- !,check_is_subset(A,Super,Hyps,PT). | |
| 1227 | check_is_subset(set_subtraction(A,_),Super,Hyps,set_sub(PT)) :- !,check_is_subset(A,Super,Hyps,PT). | |
| 1228 | check_is_subset(value(avl_set(AVL)),B,Hyps,avl) :- !,check_subset_avl(B,AVL,Hyps). | |
| 1229 | check_is_subset(A,B,Hyps,subset_eq(PT)) :- | |
| 1230 | (Operator = equal ; Operator = subset), % for subset_strict we also have subset in Hyps | |
| 1231 | % TO DO: similar rule for B | |
| 1232 | avl_fetch_binop_from_hyps(A,Operator,Hyps,S2,Hyps2), | |
| 1233 | rewrite_local_loop_check(A,check_is_subset,S2,Hyps2,Hyps3), | |
| 1234 | check_is_subset(S2,B,Hyps3,PT),!. | |
| 1235 | check_is_subset('$'(ID),B,Hyps,eq(ID,PT)) :- | |
| 1236 | get_type_from_hyps('$'(ID),Hyps,Set,Hyps2), | |
| 1237 | extract_element_super_set_type(Set,Hyps2,S2), | |
| 1238 | rewrite_local_loop_check(ID,check_is_subset,S2,Hyps2,Hyps3), | |
| 1239 | check_is_subset(S2,B,Hyps3,PT),!. | |
| 1240 | check_is_subset(domain(Func),B,Hyps,domain(PT)) :- | |
| 1241 | get_domain_or_superset(Func,Hyps,DomFunc,Hyps2), | |
| 1242 | %rewrite_local_loop_check(domain(Func),check_is_subset,DomFunc,Hyps2,Hyps3), | |
| 1243 | check_is_subset(DomFunc,B,Hyps2,PT),!. | |
| 1244 | check_is_subset(range(Func),B,Hyps,range(PT)) :- | |
| 1245 | get_range_or_superset(Func,Hyps,RanFunc,Hyps2), | |
| 1246 | %rewrite_local_loop_check(range(Func),check_is_subset,RanFunc,Hyps2,Hyps3), | |
| 1247 | check_is_subset(RanFunc,B,Hyps2,PT),!. | |
| 1248 | check_is_subset(function(Func,_),B,Hyps,function_range(PT)) :- !, | |
| 1249 | get_range_or_superset(Func,Hyps,RanFunc,Hyps2), % f : _ +-> POW(Ran) & Ran <: B => f(.) <: B | |
| 1250 | subset_transitivity_rule(RanFunc,pow_subset(B),A2,B2), % extract pow_subset from Range | |
| 1251 | check_is_subset(A2,B2,Hyps2,PT). | |
| 1252 | check_is_subset(image(Func,_),B,Hyps,image(PT)) :- % or B=range(Range) | |
| 1253 | (B = range(FuncB),check_equal(Func,FuncB,Hyps,_) -> !, PT=range_of_same_func % f[.] <: ran(f) | |
| 1254 | ; get_range_or_superset(Func,Hyps,Range,Hyps2) -> !, check_is_subset(Range,B,Hyps2,PT)). | |
| 1255 | check_is_subset(A,B,Hyps,transitivity(PT)) :- subset_transitivity_rule(A,B,A2,B2), | |
| 1256 | !, % unary subset rules like POW(A2) <: POW(B2) if A2 <: B2 | |
| 1257 | check_is_subset(A2,B2,Hyps,PT). | |
| 1258 | check_is_subset(A,B,Hyps,transitivity(PT1,PT2)) :- subset_bin_transitivity_rule(A,B,A1,A2,B1,B2), | |
| 1259 | !, % binary subset rules like A1+->B1 <: A2+->B2 if A1 <:B1 & A2 <: B2 | |
| 1260 | (check_is_subset(A1,B1,Hyps,PT1) -> check_is_subset(A2,B2,Hyps,PT2)). | |
| 1261 | check_is_subset(sorted_set_extension(List),B,Hyps,PT) :- !, | |
| 1262 | check_is_subset(set_extension(List),B,Hyps,PT). | |
| 1263 | check_is_subset(set_extension(List),B,Hyps,set_extension) :- | |
| 1264 | simplify_expr(B,Hyps,BS), % simplify expression once | |
| 1265 | %portray_hyps(Hyps),nl, | |
| 1266 | l_check_is_member(List,BS,Hyps). | |
| 1267 | check_is_subset(Sub,union(A,B),Hyps,sub_union(PT)) :- !, | |
| 1268 | ( check_is_subset(Sub,A,Hyps,PT) -> true ; check_is_subset(Sub,B,Hyps,PT)). | |
| 1269 | % get_set_of_possible_values; treat sequence_extension | |
| 1270 | check_is_subset(comprehension_set([ID],Pred),B,Hyps,comprehension_set(PT)) :- | |
| 1271 | get_conjunct(Pred,Conjunct), % TODO: also allow comprehension sets with multiple ids? | |
| 1272 | get_member(Conjunct,ID,A), | |
| 1273 | % we could do findall and then union | |
| 1274 | ID = $(ID1), \+ occurs(A,ID1), | |
| 1275 | check_is_subset(A,B,Hyps,PT). | |
| 1276 | % check_is_subset(A,B,_,_) :- print(check_is_subset_failed(A,B)),nl,nl,fail. | |
| 1277 | ||
| 1278 | get_member(member(LHS,RHS),LHS,RHS). | |
| 1279 | get_member(subset(LHS,RHS),LHS,pow_subset(RHS)). | |
| 1280 | get_member(subset_strict(LHS,RHS),LHS,pow_subset(RHS)). | |
| 1281 | ||
| 1282 | ||
| 1283 | l_check_is_member([],_,_). | |
| 1284 | l_check_is_member([El|T],B,Hyps) :- | |
| 1285 | check_member_of_set(B,El,Hyps,_ProofTree),!, | |
| 1286 | l_check_is_member(T,B,Hyps). | |
| 1287 | ||
| 1288 | % extract set type of the elements of a set: x: POW(A) ==> x<:A | |
| 1289 | extract_element_super_set_type(FuncType,Hyps,cartesian_product(A,B)) :- | |
| 1290 | get_possible_domain_of_func_or_rel_type(FuncType,Hyps,A,_),!, | |
| 1291 | get_possible_range_of_func_or_rel_type_direct(FuncType,B,_). | |
| 1292 | extract_element_super_set_type(fin_subset(A),_,A). | |
| 1293 | extract_element_super_set_type(fin1_subset(A),_,A). | |
| 1294 | extract_element_super_set_type(pow_subset(A),_,A). | |
| 1295 | extract_element_super_set_type(pow1_subset(A),_,A). | |
| 1296 | ||
| 1297 | ||
| 1298 | % simple not member of set check | |
| 1299 | check_not_member_of_set(Set,_,Hyps,empty_set) :- check_equal_empty_set(Set,Hyps,_),!. | |
| 1300 | check_not_member_of_set(Set,El,Hyps,hyp) :- | |
| 1301 | avl_fetch_from_hyps(not_member(El,Set),Hyps),!. % hyp | |
| 1302 | check_not_member_of_set(if_then_else(Pred,A,B),El,Hyps,if_then_else(PTA,PTB)) :- | |
| 1303 | push_and_rename_normalized_hyp(Pred,Hyps,Hyps1), | |
| 1304 | (hyps_inconsistent(Hyps1) -> true ; check_not_member_of_set(A,El,Hyps1,PTA) -> true), | |
| 1305 | push_and_rename_normalized_hyp(negation(Pred),Hyps,Hyps2), | |
| 1306 | (hyps_inconsistent(Hyps2) -> true ; check_not_member_of_set(B,El,Hyps2,PTB) -> true),!. | |
| 1307 | check_not_member_of_set(intersection(A,B),El,Hyps,inter(PT)) :- | |
| 1308 | (check_not_member_of_set(A,El,Hyps,PT) -> true ; check_not_member_of_set(B,El,Hyps,PT)),!. | |
| 1309 | check_not_member_of_set(set_subtraction(A,B),El,Hyps,inter(PT)) :- | |
| 1310 | (check_not_member_of_set(A,El,Hyps,PT) -> true ; check_member_of_set(B,El,Hyps,PT)),!. | |
| 1311 | check_not_member_of_set(union(A,B),El,Hyps,inter(PTA,PTB)) :- | |
| 1312 | (check_not_member_of_set(A,El,Hyps,PTA) -> check_not_member_of_set(B,El,Hyps,PTB)),!. | |
| 1313 | check_not_member_of_set(overwrite(A,B),El,Hyps,overwrite(PTA,PTB)) :- | |
| 1314 | (check_not_member_of_set(A,El,Hyps,PTA) -> check_not_member_of_set(B,El,Hyps,PTB)),!. | |
| 1315 | check_not_member_of_set('NATURAL1',El,Hyps,nat1) :- | |
| 1316 | check_leq(El,0,Hyps). | |
| 1317 | check_not_member_of_set('NATURAL',El,Hyps,nat1) :- | |
| 1318 | check_leq(El,-1,Hyps). | |
| 1319 | check_not_member_of_set(interval(From,To),El,Hyps,interval) :- | |
| 1320 | (check_leq(El,minus(From,1),Hyps) -> true | |
| 1321 | ; check_leq(add(To,1),El,Hyps) -> true). % TODO: or interval empty | |
| 1322 | check_not_member_of_set(domain(Func),El,Hyps,not_in_domain(PT)) :- | |
| 1323 | check_not_member_of_domain(Func,El,Hyps,PT),!. | |
| 1324 | check_not_member_of_set(range(Func),El,Hyps,not_in_range(PT)) :- | |
| 1325 | check_not_member_of_range(Func,El,Hyps,PT),!. | |
| 1326 | check_not_member_of_set(relations(A,B),closure(RX),Hyps,closure1_not_el_relations(PT)) :- !, | |
| 1327 | % rx : A <-> B <=> closure1(rx) : A <-> B | |
| 1328 | check_not_member_of_set(relations(A,B),RX,Hyps,PT). | |
| 1329 | check_not_member_of_set(Set,couple(From,_),Hyps,not_in_dom(PT)) :- | |
| 1330 | % x /: dom(f) => x|->y /: f | |
| 1331 | avl_fetch_binop_from_hyps(From,not_member,Hyps,Set2,Hyps2), | |
| 1332 | check_is_subset(domain(Set),Set2,Hyps2,PT), | |
| 1333 | !. | |
| 1334 | check_not_member_of_set(Set,couple(_,To),Hyps,not_in_range) :- | |
| 1335 | avl_fetch_from_hyps(not_member(To,range(Set)),Hyps), % y /: ran(f) => x|->y /: f | |
| 1336 | !. % TODO: generalise this rule somewhat, see domain above | |
| 1337 | check_not_member_of_set(A,El,Hyps,eq(ProofTree)) :- | |
| 1338 | avl_fetch_worthwhile_equal_from_hyps(A,Hyps,Value,Hyps2), | |
| 1339 | rewrite_local_loop_check(A,check_member_of_set,Value,Hyps2,Hyps3), | |
| 1340 | check_not_member_of_set(Value,El,Hyps3,ProofTree). | |
| 1341 | check_not_member_of_set(Set,El,Hyps,not_in_set_extension) :- | |
| 1342 | is_set_extension(Set,List), | |
| 1343 | check_not_member_of_list(List,El,Hyps). | |
| 1344 | %check_not_member_of_set(Set,El,Hyps,_) :- print(not_mem_failed(Set,El)),nl,fail. | |
| 1345 | % TO DO: process equalities, set_extension?, value(avl_set(AVL)), ... | |
| 1346 | ||
| 1347 | % check if an element is not in the domain of a function | |
| 1348 | check_not_member_of_domain(domain_subtraction(DS,Func),El,Hyps,not_dom_sub(PT)) :- | |
| 1349 | (check_member_of_set(DS,El,Hyps,PT) -> true | |
| 1350 | ; check_not_member_of_domain(Func,El,Hyps,PT)). | |
| 1351 | check_not_member_of_domain(domain_restriction(DS,Func),El,Hyps,not_dom_sub(PT)) :- | |
| 1352 | (check_not_member_of_set(DS,El,Hyps,PT) -> true | |
| 1353 | ; check_not_member_of_domain(Func,El,Hyps,PT)). | |
| 1354 | check_not_member_of_domain(Func,El,Hyps,PT) :- | |
| 1355 | get_domain_or_superset(Func,Hyps,DomFunc,Hyps1), | |
| 1356 | check_not_member_of_set(DomFunc,El,Hyps1,PT). | |
| 1357 | ||
| 1358 | % check if an element is not in the domain of a function | |
| 1359 | check_not_member_of_range(range_subtraction(Func,DS),El,Hyps,not_dom_sub(PT)) :- | |
| 1360 | (check_member_of_set(DS,El,Hyps,PT) -> true | |
| 1361 | ; check_not_member_of_range(Func,El,Hyps,PT)). | |
| 1362 | check_not_member_of_range(range_restriction(Func,DS),El,Hyps,not_dom_sub(PT)) :- | |
| 1363 | (check_not_member_of_set(DS,El,Hyps,PT) -> true | |
| 1364 | ; check_not_member_of_range(Func,El,Hyps,PT)). | |
| 1365 | check_not_member_of_range(Func,El,Hyps,PT) :- | |
| 1366 | get_range_or_superset(Func,Hyps,RanFunc,Hyps1),!, | |
| 1367 | check_not_member_of_set(RanFunc,El,Hyps1,PT). | |
| 1368 | ||
| 1369 | ||
| 1370 | ||
| 1371 | % check that an element does not occur in a list of values/expressions | |
| 1372 | check_not_member_of_list([],_,_). | |
| 1373 | check_not_member_of_list([H|T],El,Hyps) :- | |
| 1374 | check_not_equal(H,El,Hyps), | |
| 1375 | check_not_member_of_list(T,El,Hyps). | |
| 1376 | ||
| 1377 | is_set_extension(set_extension(List),List). | |
| 1378 | is_set_extension(sorted_set_extension(List),List). | |
| 1379 | ||
| 1380 | ||
| 1381 | % check_member_of_set(Set,Element,Hyps,ProofTree) | |
| 1382 | % check_member_of_set(A,B,_H,_ProofTree) :- print(check_member_of_set(A,B)),nl,fail. | |
| 1383 | check_member_of_set(Set,_,Hyps,maximal_set) :- maximal_set(Set,Hyps), !. | |
| 1384 | check_member_of_set(Set,if_then_else(Pred,A,B),Hyps,if(P1,P2)) :- !, % if-then-else expression | |
| 1385 | push_and_rename_normalized_hyp(Pred,Hyps,Hyps1), | |
| 1386 | (hyps_inconsistent(Hyps1) -> true ; check_member_of_set(Set,A,Hyps1,P1) -> true), | |
| 1387 | push_and_rename_normalized_hyp(negation(Pred),Hyps,Hyps2), | |
| 1388 | (hyps_inconsistent(Hyps2) -> true ; check_member_of_set(Set,B,Hyps2,P2) -> true). | |
| 1389 | check_member_of_set(Set,El,Hyps,hyp) :- | |
| 1390 | % we could do avl_fetch_binop_from_hyps(El,member,Hyps,Set2,Hyps2), and check_subset(Set2,Set) | |
| 1391 | avl_fetch_from_hyps(member(El,Set),Hyps),!. % hyp | |
| 1392 | % TO DO: sometimes value(El) stored ! | |
| 1393 | check_member_of_set(sorted_set_extension(List),El,Hyps,PT) :- !, % ordsets:ord_member(El,List),!. | |
| 1394 | check_member_of_set(set_extension(List),El,Hyps,PT). | |
| 1395 | check_member_of_set(set_extension(List),El,Hyps,set_extension) :- member(El2,List), | |
| 1396 | check_equal(El,El2,Hyps,_),!. % TO DO: avoid multiple equality rewriting of El for long lists ? | |
| 1397 | check_member_of_set(partial_function(T1,T2),El,Hyps,partial_function(PT)) :- | |
| 1398 | check_is_partial_function_with_type(El,T1,T2,Hyps,PT). | |
| 1399 | check_member_of_set(relations(A,B),closure(RX),Hyps,closure1_el_relations(PT)) :- !, | |
| 1400 | % rx : A <-> B <=> closure1(rx) : A <-> B | |
| 1401 | check_member_of_set(relations(A,B),RX,Hyps,PT). | |
| 1402 | check_member_of_set(range(Func),El,Hyps,mem_range(PT)) :- | |
| 1403 | check_member_of_range(El,Func,Hyps,PT),!. % check before function application below, can do symbolic range check | |
| 1404 | check_member_of_set(image(Func,Set),El,Hyps,mem_range_for_image(PT0,PT1)) :- | |
| 1405 | % El:ran(F) & dom(F) <: S => El:F[S] | |
| 1406 | check_member_of_set(range(Func),El,Hyps,PT0),!, | |
| 1407 | check_is_subset(domain(Func),Set,Hyps,PT1). | |
| 1408 | check_member_of_set(A,ElFunc,Hyps,typing_membership(PT)) :- | |
| 1409 | get_type_from_hyps(ElFunc,Hyps,Range,Hyps2), % !, % moving cut later proves on additional PO for test 2039 | |
| 1410 | % e.g. f(.) : A if ran(f) <: Range & Range <: A | |
| 1411 | %rewrite_local_loop_check(A,check_member_of_set,Range,Hyps2,Hyps3), | |
| 1412 | check_is_subset(Range,A,Hyps2,PT),!. | |
| 1413 | check_member_of_set(A,El,Hyps,eq(ProofTree)) :- | |
| 1414 | avl_fetch_worthwhile_equal_from_hyps(A,Hyps,Value,Hyps2), | |
| 1415 | rewrite_local_loop_check(A,check_member_of_set,Value,Hyps2,Hyps3), | |
| 1416 | check_member_of_set(Value,El,Hyps3,ProofTree). | |
| 1417 | check_member_of_set(interval(L,U),El,Hyps,interval(PT)) :- !, check_in_interval(El,L,U,Hyps,PT). | |
| 1418 | check_member_of_set('NATURAL1',El,Hyps,nat1(PT)) :- !, check_subset_interval('NATURAL1',El,El,Hyps,PT). | |
| 1419 | check_member_of_set('NATURAL',El,Hyps,nat(PT)) :- !, check_subset_interval('NATURAL',El,El,Hyps,PT). | |
| 1420 | check_member_of_set(union(A,B),El,Hyps,union(PTA,PTB)) :- !, | |
| 1421 | (check_member_of_set(A,El,Hyps,PTA) -> true ; check_member_of_set(B,El,Hyps,PTB)). | |
| 1422 | check_member_of_set(intersection(A,B),El,Hyps,intersection(PTA,PTB)) :- !, | |
| 1423 | (check_member_of_set(A,El,Hyps,PTA) -> check_member_of_set(B,El,Hyps,PTB)). | |
| 1424 | check_member_of_set(set_subtraction(A,B),El,Hyps,set_subtraction(PTA,PTB)) :- !, | |
| 1425 | (check_member_of_set(A,El,Hyps,PTA) -> check_not_member_of_set(B,El,Hyps,PTB)). | |
| 1426 | check_member_of_set(pow_subset(T1),El,Hyps,pow(PT)) :- !, | |
| 1427 | check_is_subset(El,T1,Hyps,PT). | |
| 1428 | check_member_of_set(fin_subset(T1),El,Hyps,fin(PT1,PT2)) :- !, | |
| 1429 | check_is_subset(El,T1,Hyps,PT1),!, | |
| 1430 | check_finite(El,Hyps,PT2). | |
| 1431 | check_member_of_set(pow1_subset(T1),El,Hyps,pow1(PT)) :- !, | |
| 1432 | check_not_empty_set(El,Hyps),!, | |
| 1433 | check_is_subset(El,T1,Hyps,PT). | |
| 1434 | check_member_of_set(fin1_subset(T1),El,Hyps,fin1(PT1,PT2)) :- !, | |
| 1435 | check_not_empty_set(El,Hyps),!, | |
| 1436 | check_is_subset(El,T1,Hyps,PT1),!, | |
| 1437 | check_finite(El,Hyps,PT2). | |
| 1438 | check_member_of_set(seq(T1),El,Hyps,seq(PT)) :- !, | |
| 1439 | check_is_sequence(El,Hyps),!, | |
| 1440 | check_is_subset(range(El),T1,Hyps,PT). | |
| 1441 | check_member_of_set(seq1(T1),El,Hyps,seq1(PT)) :- !, | |
| 1442 | check_is_non_empty_sequence(El,Hyps),!, | |
| 1443 | check_is_subset(range(El),T1,Hyps,PT). | |
| 1444 | check_member_of_set(cartesian_product(T1,T2),couple(El1,El2),Hyps,cart(PT1,PT2)) :- !, | |
| 1445 | check_member_of_set(T1,El1,Hyps,PT1),!, | |
| 1446 | check_member_of_set(T2,El2,Hyps,PT2). | |
| 1447 | check_member_of_set(value(avl_set(AVL)),El,Hyps,PT) :- | |
| 1448 | (avl_can_fetch(El,BVal) -> !,PT=avl_fetch(El),avl_fetch(BVal,AVL) | |
| 1449 | ; avl_is_interval(AVL,Min,Max) -> !, PT=avl_interval(PT2), | |
| 1450 | % useful is El is not a number, but e.g. an arithmetic expression | |
| 1451 | % print(avl_interval(Min,Max,El)),nl, | |
| 1452 | check_integer(El,check_member_of_set_avl_interval), | |
| 1453 | check_in_interval(El,Min,Max,Hyps,PT2) | |
| 1454 | ). | |
| 1455 | check_member_of_set(A,El,Hyps,rewrite(PT)) :- rewrite_set_expression_exact(A,Hyps,A2,Hyps2),!, | |
| 1456 | check_member_of_set(A2,El,Hyps2,PT). | |
| 1457 | check_member_of_set(domain(Func),Index,Hyps,mem_domain(PT)) :- | |
| 1458 | check_member_of_domain(Index,Func,Hyps,PT),!. | |
| 1459 | check_member_of_set(Set,X,Hyps,value_set(PT)) :- | |
| 1460 | try_get_set_of_possible_values(X,Hyps,XSet,Hyps2), % also covers min(Set), max(Set), mu(Set), CHOOSE(Set) | |
| 1461 | check_is_subset(XSet,Set,Hyps2,PT),!. | |
| 1462 | %check_member_of_set(Set,X,Hyps,eq(PT)) :- Set = '$'(_), | |
| 1463 | % avl_fetch_equal_from_hyps(Set,Hyps,Set2,Hyps2), % maybe perform direct rewrite ancestor cycle check here | |
| 1464 | % check_member_of_set(Set2,X,Hyps2,PT),!. | |
| 1465 | check_member_of_set(Set,X,Hyps,trans(PT)) :- | |
| 1466 | avl_fetch_binop_from_hyps(Set,superset,Hyps,SubSet,Hyps2), % X:B & B <: A => X:A | |
| 1467 | check_member_of_set(SubSet,X,Hyps2,PT),!. | |
| 1468 | check_member_of_set(Set,ID,Hyps,member_subset(PT)) :- | |
| 1469 | avl_fetch_worthwhile_member_from_hyps(ID,Hyps,SubSet,Hyps2), %write(sub(ID,SubSet,Set)),nl, | |
| 1470 | check_is_subset(SubSet,Set,Hyps2,PT). | |
| 1471 | %check_member_of_set(A,B,_H,_ProofTree) :- print(check_member_of_set_failed(A,B)),nl,fail. | |
| 1472 | ||
| 1473 | ||
| 1474 | :- use_module(probsrc(kernel_reals),[construct_real/2]). | |
| 1475 | % check if we can fetch an expression as a B value (second arg) in an AVL set | |
| 1476 | avl_can_fetch(El,Res) :- number(El),!, Res=int(El). | |
| 1477 | avl_can_fetch(boolean_true,pred_true). | |
| 1478 | avl_can_fetch(boolean_false,pred_false). | |
| 1479 | avl_can_fetch(real(Atom),R) :- construct_real(Atom,R). | |
| 1480 | avl_can_fetch(string(S),string(S)) :- ground(S). | |
| 1481 | avl_can_fetch(couple(A,B),(VA,VB)) :- avl_can_fetch(A,VA), avl_can_fetch(B,VB). | |
| 1482 | ||
| 1483 | check_member_of_domain(El,reverse(Func2),Hyps,reverse(PT)) :- !, | |
| 1484 | check_member_of_range(El,Func2,Hyps,PT). | |
| 1485 | check_member_of_domain(El,Func,Hyps,hyp) :- | |
| 1486 | avl_fetch_from_hyps(member(El,domain(Func)),Hyps),!. % hyp, already checked in check_member_of_set | |
| 1487 | check_member_of_domain(Index,Func,Hyps,size_in_dom_seq) :- % x:seq1(T) => size(x) : dom(x) | |
| 1488 | index_in_non_empty_sequence(Index,Func,Hyps), | |
| 1489 | check_is_non_empty_sequence(Func,Hyps),!. | |
| 1490 | % TO DO: f~(x) : dom(f) ?? | |
| 1491 | check_member_of_domain(El,union(A,B),Hyps,dom_of_union(PT)) :- | |
| 1492 | check_member_of_union(domain(A),domain(B),El,Hyps,PT). | |
| 1493 | check_member_of_domain(El,overwrite(A,B),Hyps,dom_of_overwrite(PT)) :- | |
| 1494 | check_member_of_union(domain(A),domain(B),El,Hyps,PT). | |
| 1495 | check_member_of_domain(El,direct_product(A,B),Hyps,dom_of_direct_product(PT)) :- % dom(A >< B) = dom(A) /\ dom (B) | |
| 1496 | check_member_of_set(domain(A),El,Hyps,PT), | |
| 1497 | check_member_of_set(domain(B),El,Hyps,PT). | |
| 1498 | check_member_of_domain(El,A,Hyps,rewrite(PT)) :- rewrite_set_expression_exact(A,Hyps,A2,Hyps2),!, | |
| 1499 | check_member_of_domain(El,A2,Hyps2,PT). | |
| 1500 | check_member_of_domain(El,Func,Hyps,dom_of_subset(PT)) :- % Func2 <: Func & El:dom(Func2) => El:dom(Func) | |
| 1501 | % counter part of rule with superset for check_member_of_set | |
| 1502 | (Op = equal ; Op = superset), | |
| 1503 | avl_fetch_binop_from_hyps(Func,Op,Hyps,Func2,Hyps1), | |
| 1504 | rewrite_local_loop_check(Func,check_member_of_domain,Func2,Hyps1,Hyps2), | |
| 1505 | check_member_of_set(domain(Func2),El,Hyps2,PT). | |
| 1506 | check_member_of_domain(El,comprehension_set(IDS,Body),Hyps,dom_of_lambda(PTs)) :- | |
| 1507 | get_lambda_args_and_body(IDS,Body,_,_,Args,RestBodyList), | |
| 1508 | %nl,print(lambda(Args,El,RestBodyList)),nl, | |
| 1509 | generate_funapp_binding(Args,El,Subst), | |
| 1510 | % we rename the local variables of the comprehension set; no need to call add_new_hyp_any_vars | |
| 1511 | l_rename_and_prove_goals(RestBodyList,Subst,Hyps,PTs). | |
| 1512 | check_member_of_domain(El,restrict_front(_,K),Hyps,dom_of_restrict_front(PT)) :- | |
| 1513 | check_member_of_set(interval(1,K),El,Hyps,PT). % WD Condition requires K : 0..size(Seq) | |
| 1514 | check_member_of_domain(El,if_then_else(Pred,A,B),Hyps,if_then_else(PT1,PT2)) :- | |
| 1515 | push_and_rename_normalized_hyp(Pred,Hyps,Hyps1), | |
| 1516 | (hyps_inconsistent(Hyps1) -> true ; check_member_of_domain(El,A,Hyps1,PT1) -> true), | |
| 1517 | push_and_rename_normalized_hyp(negation(Pred),Hyps,Hyps2), | |
| 1518 | (hyps_inconsistent(Hyps2) -> true ; check_member_of_domain(El,B,Hyps2,PT2) -> true). | |
| 1519 | %check_member_of_domain(Index,Func,Hyps,_) :- write(check_member_of_domain_failed(Index,Func)),nl,fail. | |
| 1520 | ||
| 1521 | % we could do intersection, subtraction | |
| 1522 | ||
| 1523 | % check if an element is an element of a union of two sets | |
| 1524 | check_member_of_union(Set1,_,El,Hyps,PT) :- check_member_of_set(Set1,El,Hyps,PT),!. | |
| 1525 | check_member_of_union(_,Set2,El,Hyps,PT) :- check_member_of_set(Set2,El,Hyps,PT),!. | |
| 1526 | check_member_of_union(Set1,Set2,El,Hyps,union(PT1,PT2)) :- | |
| 1527 | % x : A \/ B & A <: S1 & B <: S2 => x : S1 \/ S2 | |
| 1528 | avl_fetch_mem_from_hyps(El,Hyps,union(A,B),Hyps2), % TO DO: other conditions ? | |
| 1529 | (check_is_subset(A,Set1,Hyps2,PT1) -> check_is_subset(B,Set2,Hyps2,PT2) | |
| 1530 | ; check_is_subset(A,Set2,Hyps2,PT1) -> check_is_subset(B,Set1,Hyps2,PT2)). | |
| 1531 | ||
| 1532 | generate_funapp_binding(['$'(X)],El,[rename(X,El)]). | |
| 1533 | generate_funapp_binding(['$'(X),'$'(Y)],couple(El1,El2),[rename(X,El1),rename(Y,El2)]). | |
| 1534 | generate_funapp_binding(['$'(X),'$'(Y),'$'(Z)],couple(couple(El1,El2),El3),[rename(X,El1),rename(Y,El2),rename(Z,El3)]). | |
| 1535 | % TO DO: create substitution for more arguments and other parameters | |
| 1536 | ||
| 1537 | ||
| 1538 | check_member_of_range(El,reverse(Func2),Hyps,reverse(PT)) :- !,check_member_of_domain(El,Func2,Hyps,PT). | |
| 1539 | check_member_of_range(El,Func,Hyps,hyp) :- | |
| 1540 | avl_fetch_from_hyps(member(El,range(Func)),Hyps),!. % hyp, already checked in check_member_of_set | |
| 1541 | check_member_of_range(El,A,Hyps,rewrite(PT)) :- rewrite_set_expression_exact(A,Hyps,A2,Hyps2),!, | |
| 1542 | check_member_of_range(El,A2,Hyps2,PT). | |
| 1543 | check_member_of_range('$'(ID),Func2,Hyps,PT) :- | |
| 1544 | avl_fetch_worthwhile_equal_from_hyps('$'(ID),Hyps,Value,Hyps2), | |
| 1545 | check_member_of_range(Value,Func2,Hyps2,PT). | |
| 1546 | check_member_of_range(function(Func1,_),Func2,Hyps,func_app_in_range) :- % f(.) : ran(f) | |
| 1547 | check_equal(Func1,Func2,Hyps,_). | |
| 1548 | check_member_of_range(El,if_then_else(Pred,A,B),Hyps,if_then_else(PT1,PT2)) :- | |
| 1549 | push_and_rename_normalized_hyp(Pred,Hyps,Hyps1), | |
| 1550 | (hyps_inconsistent(Hyps1) -> true ; check_member_of_range(El,A,Hyps1,PT1) -> true), | |
| 1551 | push_and_rename_normalized_hyp(negation(Pred),Hyps,Hyps2), | |
| 1552 | (hyps_inconsistent(Hyps2) -> true ; check_member_of_range(El,B,Hyps2,PT2) -> true). | |
| 1553 | ||
| 1554 | ||
| 1555 | % subset transitivity for unary operators: | |
| 1556 | subset_transitivity_rule(pow_subset(A),pow_subset(B),A,B). | |
| 1557 | ||
| 1558 | subset_transitivity_rule(pow1_subset(A),pow1_subset(B),A,B). | |
| 1559 | subset_transitivity_rule(pow1_subset(A),pow_subset(B),A,B). | |
| 1560 | ||
| 1561 | subset_transitivity_rule(fin_subset(A),fin_subset(B),A,B). | |
| 1562 | subset_transitivity_rule(fin_subset(A),pow_subset(B),A,B). | |
| 1563 | ||
| 1564 | subset_transitivity_rule(fin1_subset(A),fin1_subset(B),A,B). | |
| 1565 | subset_transitivity_rule(fin1_subset(A),fin_subset(B),A,B). | |
| 1566 | subset_transitivity_rule(fin1_subset(A),pow1_subset(B),A,B). | |
| 1567 | subset_transitivity_rule(fin1_subset(A),pow_subset(B),A,B). | |
| 1568 | ||
| 1569 | subset_transitivity_rule(seq(A),seq(B),A,B). | |
| 1570 | subset_transitivity_rule(seq(A),partial_function(typeset,B),A,B). | |
| 1571 | ||
| 1572 | subset_transitivity_rule(seq1(A),seq1(B),A,B). | |
| 1573 | subset_transitivity_rule(seq1(A),seq(B),A,B). | |
| 1574 | subset_transitivity_rule(seq1(A),partial_function(typeset,B),A,B). | |
| 1575 | ||
| 1576 | subset_transitivity_rule(iseq(A),iseq(B),A,B). | |
| 1577 | subset_transitivity_rule(iseq(A),seq(B),A,B). | |
| 1578 | subset_transitivity_rule(iseq(A),partial_function(typeset,B),A,B). | |
| 1579 | ||
| 1580 | subset_transitivity_rule(iseq1(A),iseq1(B),A,B). | |
| 1581 | subset_transitivity_rule(iseq1(A),iseq(B),A,B). | |
| 1582 | subset_transitivity_rule(iseq1(A),seq1(B),A,B). | |
| 1583 | subset_transitivity_rule(iseq1(A),seq(B),A,B). | |
| 1584 | subset_transitivity_rule(iseq1(A),partial_function(typeset,B),A,B). | |
| 1585 | ||
| 1586 | % subset_transitivity_rule(perm(A),perm(B),A,B). % this does not hold perm({}) = { [] }, perm({TRUE}) = {[TRUE]} | |
| 1587 | subset_transitivity_rule(perm(A),iseq(B),A,B). | |
| 1588 | subset_transitivity_rule(perm(A),seq(B),A,B). | |
| 1589 | subset_transitivity_rule(perm(A),partial_function(typeset,B),A,B). | |
| 1590 | ||
| 1591 | ||
| 1592 | subset_transitivity_rule(range(A),domain(reverse(B)),A,B). | |
| 1593 | subset_transitivity_rule(range(A),range(B),A,B). | |
| 1594 | subset_transitivity_rule(range(reverse(A)),domain(B),A,B). | |
| 1595 | subset_transitivity_rule(domain(reverse(A)),range(B),A,B). | |
| 1596 | subset_transitivity_rule(domain(A),domain(B),A,B). % dom(A) <: dom(B) if A <:B | |
| 1597 | subset_transitivity_rule(domain(A),range(reverse(B)),A,B). | |
| 1598 | subset_transitivity_rule(reverse(A),reverse(B),A,B). | |
| 1599 | subset_transitivity_rule(rev(A),rev(B),A,B). | |
| 1600 | subset_transitivity_rule(identity(A),identity(B),A,B). | |
| 1601 | ||
| 1602 | % TO DO: add rules for more binary operators, like surjective relations, ... | |
| 1603 | subset_bin_transitivity_rule(relations(A1,A2),relations(B1,B2),A1,A2,B1,B2). % <-> | |
| 1604 | subset_bin_transitivity_rule(total_relation(A1,A2),relations(B1,B2),A1,A2,B1,B2). % <<-> | |
| 1605 | subset_bin_transitivity_rule(total_relation(A1,A2),total_relation(B1,B2),A1,A2,B1,B2) :- A1=B1. | |
| 1606 | subset_bin_transitivity_rule(partial_function(A1,A2),relations(B1,B2),A1,A2,B1,B2). % +-> | |
| 1607 | subset_bin_transitivity_rule(partial_function(A1,A2),partial_function(B1,B2),A1,A2,B1,B2). | |
| 1608 | subset_bin_transitivity_rule(partial_injection(A1,A2),partial_function(B1,B2),A1,A2,B1,B2). % >+> | |
| 1609 | subset_bin_transitivity_rule(partial_injection(A1,A2),partial_injection(B1,B2),A1,A2,B1,B2). | |
| 1610 | subset_bin_transitivity_rule(partial_surjection(A1,A2),partial_function(B1,B2),A1,A2,B1,B2). % -+>> | |
| 1611 | subset_bin_transitivity_rule(partial_surjection(A1,A2),partial_surjection(B1,B2),A1,A2,B1,B2) :- A2=B2. | |
| 1612 | subset_bin_transitivity_rule(partial_bijection(A1,A2),partial_function(B1,B2),A1,A2,B1,B2). % >+>> | |
| 1613 | subset_bin_transitivity_rule(total_function(A1,A2),partial_function(B1,B2),A1,A2,B1,B2). % --> | |
| 1614 | subset_bin_transitivity_rule(total_function(A1,A2),total_function(B1,B2),A1,A2,B1,B2) :- A1=B1. | |
| 1615 | subset_bin_transitivity_rule(total_injection(A1,A2),partial_function(B1,B2),A1,A2,B1,B2). % >-> | |
| 1616 | subset_bin_transitivity_rule(total_injection(A1,A2),total_function(B1,B2),A1,A2,B1,B2) :- A1=B1. | |
| 1617 | subset_bin_transitivity_rule(total_surjection(A1,A2),partial_function(B1,B2),A1,A2,B1,B2). % -->> | |
| 1618 | subset_bin_transitivity_rule(total_surjection(A1,A2),total_function(B1,B2),A1,A2,B1,B2) :- A1=B1. | |
| 1619 | subset_bin_transitivity_rule(total_bijection(A1,A2),partial_function(B1,B2),A1,A2,B1,B2). % >+>> | |
| 1620 | subset_bin_transitivity_rule(total_bijection(A1,A2),partial_injection(B1,B2),A1,A2,B1,B2). | |
| 1621 | subset_bin_transitivity_rule(total_bijection(A1,A2),partial_surjection(B1,B2),A1,A2,B1,B2) :- A2=B2. | |
| 1622 | subset_bin_transitivity_rule(total_bijection(A1,A2),total_function(B1,B2),A1,A2,B1,B2) :- A1=B1. | |
| 1623 | subset_bin_transitivity_rule(total_bijection(A1,A2),total_injection(B1,B2),A1,A2,B1,B2) :- A1=B1. | |
| 1624 | subset_bin_transitivity_rule(total_bijection(A1,A2),total_surjection(B1,B2),A1,A2,B1,B2) :- A1=B1, A2=B2. | |
| 1625 | subset_bin_transitivity_rule(image(A1,A2),image(B1,B2),A1,A2,B1,B2). % A1[A2] <: B1[B2] if A1 <: B1 & A2 <: B2 | |
| 1626 | subset_bin_transitivity_rule(domain_restriction(A1,A2),domain_restriction(B1,B2),A1,A2,B1,B2). % A1 <| A2 <: B1 <| B2 if A1 <: B1 & A2 <: B2 | |
| 1627 | subset_bin_transitivity_rule(range_restriction(A1,A2),range_restriction(B1,B2),A1,A2,B1,B2). | |
| 1628 | subset_bin_transitivity_rule(domain_subtraction(A1,A2),domain_subtraction(B1,B2),B1,A2,A1,B2). % A1 <<| A2 <: B1 <<| B2 if B1 <: A1 & A2 <: B2 | |
| 1629 | subset_bin_transitivity_rule(range_subtraction(A1,A2),range_subtraction(B1,B2),A1,B2,A2,B1). % A1 |>> A2 <: B1|>> B2 if A1 <: B1 & B2 <: A2 | |
| 1630 | %subset_bin_transitivity_rule(A,B,A1,A2,B1,B2) :- write(subset_bin_transitivity_rule(A,B,A1,A2,B1,B2)),nl,fail. | |
| 1631 | % TO DO: add more | |
| 1632 | ||
| 1633 | % TO DO: instead of is_set_of_sequences_type | |
| 1634 | %subset_mixed_transitivity_rule(total_function(A1,A2),seq(B2),A2,B2) :- is_interval(A1). | |
| 1635 | ||
| 1636 | check_in_interval(El,Min,Max,Hyps,in_interval(PT1,PT2)) :- | |
| 1637 | expr_is_member_of_set(El,Set,PT1),!, % TODO: should we treat min/max as well here?? | |
| 1638 | check_is_subset(Set,interval(Min,Max),Hyps,PT2). | |
| 1639 | check_in_interval(El,Min,Max,Hyps,PT) :- | |
| 1640 | check_subset_interval(interval(Min,Max),El,El,Hyps,PT). % calls check_sub_intervals(Min,Max,El,El,Hyps) | |
| 1641 | ||
| 1642 | expr_is_member_of_set(mu(Set),Set,mu). | |
| 1643 | expr_is_member_of_set(external_function_call(Call,[Set]),Set,ext_call(Call)) :- | |
| 1644 | (Call = 'CHOOSE' -> true ; Call = 'MU'). | |
| 1645 | ||
| 1646 | % check if an interval is a subset of the first argument | |
| 1647 | check_subset_interval(union(A,B),L1,U1,Hyps,union(PT)) :- !, | |
| 1648 | % TO DO: try and merge A,B : union(interval(1,10),set_extension([11])) | |
| 1649 | (check_subset_interval(A,L1,U1,Hyps,PT) -> true ; check_subset_interval(B,L1,U1,Hyps,PT)). | |
| 1650 | check_subset_interval(sorted_set_extension(L),L1,U1,Hyps,PT) :- !, | |
| 1651 | check_subset_interval(set_extension(L),L1,U1,Hyps,PT). | |
| 1652 | check_subset_interval(set_extension(L),L1,U1,Hyps,set_extension(Nr)) :- !, | |
| 1653 | % TO DO: maybe merge L into an interval | |
| 1654 | nth1(Nr,L,El), check_sub_intervals(L1,U1,El,El,Hyps),!. | |
| 1655 | check_subset_interval(intersection(A,B),L1,U1,Hyps,inter(PTA,PTB)) :- !, | |
| 1656 | % L1..U1 <: A /\ B if L1..U1 <: A & L1..U1 <: B | |
| 1657 | (check_subset_interval(A,L1,U1,Hyps,PTA) -> check_subset_interval(B,L1,U1,Hyps,PTB)). | |
| 1658 | check_subset_interval(interval(L2,U2),L1,U1,Hyps,interval) :- | |
| 1659 | !,check_sub_intervals(L1,U1,L2,U2,Hyps). | |
| 1660 | check_subset_interval('NATURAL',L1,_,Hyps,nat) :- !, check_leq(0,L1,Hyps). | |
| 1661 | check_subset_interval('NATURAL1',L1,_,Hyps,nat1) :- !, check_leq(1,L1,Hyps). | |
| 1662 | check_subset_interval(value(avl_set(A)),L1,U1,Hyps,avl(PT)) :- !, | |
| 1663 | (number(L1), number(U1) | |
| 1664 | -> PT=in(L1,U1), | |
| 1665 | check_interval_in_custom_set(L1,U1,avl_set(A),no_wf_available) | |
| 1666 | ; avl_min(A,int(L2)), avl_max(A,int(U2)), PT=min_max(L2,U2,PT2), | |
| 1667 | check_subset_interval(interval(L2,U2),L1,U1,Hyps,PT2) | |
| 1668 | ). | |
| 1669 | check_subset_interval(A,L1,U1,Hyps,rewrite(PT)) :- rewrite_set_expression_exact(A,Hyps,A2,Hyps2),!, | |
| 1670 | check_subset_interval(A2,L1,U1,Hyps2,PT). | |
| 1671 | check_subset_interval(domain(Expr),Low,Up,Hyps,dom_seq1) :- % a special rule when using SEQ(1) rather than first(SEQ) | |
| 1672 | (check_leq(1,Low,Hyps), check_leq(Up,size(Expr),Hyps) % 1..size(s) <: dom(s) | |
| 1673 | -> check_is_sequence(Expr,Hyps) | |
| 1674 | ; index_in_non_empty_sequence(Low,Expr,Hyps), | |
| 1675 | index_in_non_empty_sequence(Up,Expr,Hyps) % 1..1 or size(s)..size(s) <: dom(s) if s:seq1(.) | |
| 1676 | -> check_is_non_empty_sequence(Expr,Hyps) | |
| 1677 | ). | |
| 1678 | check_subset_interval(range(reverse(Expr)),Low,Up,Hyps,PT) :- !, | |
| 1679 | check_subset_interval(domain(Expr),Low,Up,Hyps,PT). | |
| 1680 | check_subset_interval(A,Low,Up,Hyps,eq(PT)) :- | |
| 1681 | avl_fetch_worthwhile_equal_from_hyps(A,Hyps,A2,Hyps2), | |
| 1682 | rewrite_local_loop_check(A,check_subset_interval,A2,Hyps2,Hyps3), | |
| 1683 | check_subset_interval(A2,Low,Up,Hyps3,PT). | |
| 1684 | %check_subset_interval(A,L1,U1,_,_) :- print(check_subset_interval_failed(A,L1,U1)),nl,fail. | |
| 1685 | ||
| 1686 | % s:seq1(.) => 1:dom(s) & size(s):dom(s) | |
| 1687 | index_in_non_empty_sequence(1,_,_). | |
| 1688 | index_in_non_empty_sequence(card(E),E,_). | |
| 1689 | index_in_non_empty_sequence(size(E),E,_). | |
| 1690 | index_in_non_empty_sequence('$'(X),E,Hyps) :- | |
| 1691 | avl_fetch_equal_from_hyps('$'(X),Hyps,Y,Hyps2), | |
| 1692 | rewrite_local_loop_check(X,index_in_non_empty_sequence,Y,Hyps2,Hyps3), | |
| 1693 | index_in_non_empty_sequence(Y,E,Hyps3). | |
| 1694 | index_in_non_empty_sequence(X,E,Hyps) :- \+ useful_value(X), % do not rewrite 10 to interval(10,10) | |
| 1695 | try_get_set_of_possible_values(X,Hyps,XSet,Hyps2), | |
| 1696 | rewrite_local_loop_check(X,index_in_non_empty_sequence,XSet,Hyps2,Hyps3), | |
| 1697 | all_in_non_empty_sequence(XSet,E,Hyps3). | |
| 1698 | ||
| 1699 | all_in_non_empty_sequence(interval(A,B),E,Hyps) :- | |
| 1700 | index_in_non_empty_sequence(A,E,Hyps), | |
| 1701 | index_in_non_empty_sequence(B,E,Hyps). | |
| 1702 | % TODO: avl_set, ... | |
| 1703 | ||
| 1704 | % check if L1..U1 <: L2..U2 | |
| 1705 | check_sub_intervals(L1,L1,L2,U2,Hyps) :- (L1=L2 ; L1=U2),!, | |
| 1706 | check_not_empty_set(interval(L2,U2),Hyps). | |
| 1707 | check_sub_intervals(L1,U1,L2,U2,Hyps) :- % L1..U1 <: L2..U2 if L2 <= L1 & U1 <= U2 | |
| 1708 | check_leq(L2,L1,Hyps),!, | |
| 1709 | check_leq(U1,U2,Hyps). | |
| 1710 | ||
| 1711 | ||
| 1712 | ||
| 1713 | % some exact rewrite steps | |
| 1714 | rewrite_set_expression_exact(domain(A),Hyps,Res,Hyps2) :- compute_exact_domain(A,Hyps,Dom,Hyps2),!, | |
| 1715 | %print(rewrote(domain(A))),nl, print(Dom),nl, | |
| 1716 | (A='$'(ID) -> not_occurs(Dom,ID) ; true), % prevent silly rewrites | |
| 1717 | Res=Dom. | |
| 1718 | rewrite_set_expression_exact(range(A),Hyps,Res,Hyps2) :- compute_exact_range(A,Hyps,Ran,Hyps2),!, | |
| 1719 | %print(rewrote(range(A))),nl, print(Ran),nl, | |
| 1720 | (A='$'(ID) -> not_occurs(Ran,ID) ; true), % prevent silly rewrites | |
| 1721 | Res=Ran. | |
| 1722 | rewrite_set_expression_exact(intersection(A,B),Hyps,Res,Hyps) :- | |
| 1723 | (is_empty_set_direct(A) -> Res=empty_set ; is_empty_set_direct(B) -> Res=empty_set). | |
| 1724 | rewrite_set_expression_exact(set_subtraction(A,B),Hyps,Res,Hyps) :- | |
| 1725 | (is_empty_set_direct(A) -> Res=empty_set ; is_empty_set_direct(B) -> Res=A). | |
| 1726 | rewrite_set_expression_exact(union(A,B),Hyps,Res,Hyps1) :- | |
| 1727 | (check_equal(A,B,Hyps,Hyps1) -> Res=A | |
| 1728 | ; Hyps1=Hyps, merge_set_extensions(union(A,B),List,[]), | |
| 1729 | construct_set_extension(List,Hyps,Res)). | |
| 1730 | rewrite_set_expression_exact(value(closure(P,T,B)),Hyps,Res,Hyps) :- nonvar(P), | |
| 1731 | is_interval_closure(P,T,B,LOW,UP), number(LOW),number(UP),!, | |
| 1732 | Res = interval(LOW,UP). | |
| 1733 | rewrite_set_expression_exact(assertion_expression(_,_,Expr),Hyps,Res,Hyps2) :- % TO DO: add Predicate to Hyps ? | |
| 1734 | (rewrite_set_expression_exact(Expr,Hyps,Expr2,Hyps2) -> Res=Expr2 | |
| 1735 | ; Res=Expr, Hyps2=Hyps). | |
| 1736 | rewrite_set_expression_exact(Expr,Hyps,Res,Hyps) :- | |
| 1737 | eval_bvalue_from_norm_expr(Expr,Val),!, Res=value(Val). | |
| 1738 | % Note one can have equalities like f = f~~ (in FunLawsWithLambda.mch); hence important to pass Hyps for cycle detection | |
| 1739 | ||
| 1740 | % rewrite relational image operator | |
| 1741 | rewrite_rel_image(Rel,Set,Hyps,value(ResVal),Hyps) :- | |
| 1742 | get_bvalue_from_norm_expr(Rel,RelVal), get_bvalue_from_norm_expr(Set,SetVal), | |
| 1743 | eval_binary_operator(image,RelVal,SetVal,ResVal). | |
| 1744 | ||
| 1745 | ||
| 1746 | eval_unary_operator(reverse,Arg,Res) :- bsets_clp:invert_relation_wf(Arg,Res,no_wf_available). | |
| 1747 | eval_binary_operator(image,RelVal,SetVal,Res) :- bsets_clp:image_wf(RelVal,SetVal,Res,no_wf_available). | |
| 1748 | ||
| 1749 | % try and convert a normed AST expression to a valid B value | |
| 1750 | get_bvalue_from_norm_expr(boolean_true,pred_true). | |
| 1751 | get_bvalue_from_norm_expr(boolean_false,pred_false). | |
| 1752 | get_bvalue_from_norm_expr(Nr,int(Nr)) :- integer(Nr). | |
| 1753 | get_bvalue_from_norm_expr(value(V),V). | |
| 1754 | get_bvalue_from_norm_expr(set_extension(List),Result) :- maplist(get_bvalue_from_norm_expr,List,Result). | |
| 1755 | get_bvalue_from_norm_expr(sorted_set_extension(List),Result) :- maplist(get_bvalue_from_norm_expr,List,Result). | |
| 1756 | get_bvalue_from_norm_expr(Expr,Res) :- eval_bvalue_from_norm_expr(Expr,Res). | |
| 1757 | ||
| 1758 | eval_bvalue_from_norm_expr(reverse(Rel),ResVal) :- get_bvalue_from_norm_expr(Rel,RelVal), | |
| 1759 | eval_unary_operator(reverse,RelVal,ResVal). | |
| 1760 | eval_bvalue_from_norm_expr(image(Rel,Set),ResVal) :- get_bvalue_from_norm_expr(Rel,RelVal), | |
| 1761 | get_bvalue_from_norm_expr(Set,SetVal), | |
| 1762 | eval_binary_operator(image,RelVal,SetVal,ResVal). | |
| 1763 | ||
| 1764 | ||
| 1765 | % try and rewrite function applications for comprehension_sets | |
| 1766 | rewrite_function_application(comprehension_set([$(PARA),$(LAMBDARES)],Body),Arg,Hyps,Result,Hyps) :- | |
| 1767 | get_conjunct(Body,equal(A,B)), | |
| 1768 | sym_unify(A,B,$(LAMBDARES),RESEXPR), | |
| 1769 | \+ occurs(RESEXPR,LAMBDARES), | |
| 1770 | % TODO: support more than one argument and hadd rest of body to hyps | |
| 1771 | !, | |
| 1772 | rename_norm_term(RESEXPR,[rename(PARA,Arg)],Result). | |
| 1773 | rewrite_function_application(Function,Arg,Hyps,Result,Hyps2) :- | |
| 1774 | avl_fetch_binop_from_hyps(Function,equal,Hyps,Value,Hyps1), | |
| 1775 | rewrite_function_application(Value,Arg,Hyps1,Result,Hyps2). | |
| 1776 | ||
| 1777 | get_conjunct(conjunct(A,B),C) :- !, (get_conjunct(A,C) ; get_conjunct(B,C)). | |
| 1778 | get_conjunct(C,C). | |
| 1779 | ||
| 1780 | merge_set_extensions(empty_set) --> []. | |
| 1781 | merge_set_extensions(empty_sequence) --> []. | |
| 1782 | merge_set_extensions(set_extension(L)) --> L. | |
| 1783 | merge_set_extensions(sorted_set_extension(L)) --> L. | |
| 1784 | merge_set_extensions(union(A,B)) --> merge_set_extensions(A), merge_set_extensions(B). | |
| 1785 | ||
| 1786 | % check if AVL is a subset of the first argument | |
| 1787 | check_subset_avl(union(A,B),AVL1,Hyps) :- !, % TO DO: try and merge A,B | |
| 1788 | (check_subset_avl(A,AVL1,Hyps) -> true ; check_subset_avl(B,AVL1,Hyps)). | |
| 1789 | check_subset_avl(intersection(A,B),AVL1,Hyps) :- !, % AVL <: A /\ B if AVL <: A & AVL <: B | |
| 1790 | (check_subset_avl(A,AVL1,Hyps) -> check_subset_avl(B,AVL1,Hyps)). | |
| 1791 | check_subset_avl(interval(L2,U2),AVL,_) :- number(L2),number(U2),!, | |
| 1792 | check_avl_in_interval(AVL,L2,U2). | |
| 1793 | check_subset_avl(value(avl_set(AVL2)),AVL1,_) :- !, check_avl_subset(AVL1,AVL2). | |
| 1794 | check_subset_avl(seq(MAX),AVL,Hyps) :- maximal_set(MAX,Hyps), !, is_avl_set_of_sequences(AVL,seq). | |
| 1795 | check_subset_avl(seq1(MAX),AVL,Hyps) :- maximal_set(MAX,Hyps), !, is_avl_set_of_sequences(AVL,seq1). | |
| 1796 | check_subset_avl(seq(seq(MAX)),AVL,Hyps) :- maximal_set(MAX,Hyps), | |
| 1797 | % comes from general concat | |
| 1798 | custom_explicit_sets:is_one_element_avl(AVL,Element), % usually one value from try_get_set_of_possible_values | |
| 1799 | is_sequence(Element,seq), | |
| 1800 | expand_custom_set_to_list(Element,ListOfSeqs), | |
| 1801 | maplist(is_subsequence,ListOfSeqs). | |
| 1802 | check_subset_avl(A,AVL,Hyps) :- rewrite_set_expression_exact(A,Hyps,A2,Hyps2),!, | |
| 1803 | check_subset_avl(A2,AVL,Hyps2). | |
| 1804 | check_subset_avl(A,AVL,Hyps) :- | |
| 1805 | avl_fetch_worthwhile_equal_from_hyps(A,Hyps,A2,Hyps2), | |
| 1806 | rewrite_local_loop_check(A,check_subset_avl,A2,Hyps2,Hyps3), | |
| 1807 | check_subset_avl(A2,AVL,Hyps3). | |
| 1808 | %check_subset_avl(A,AVL,_) :- print(check_subset_avl_failed(A,AVL)),nl,fail. | |
| 1809 | ||
| 1810 | is_subsequence((int(_Index),Sequence)) :- is_sequence(Sequence,seq). | |
| 1811 | ||
| 1812 | is_sequence(avl_set(SeqAVL),_) :- safe_is_avl_sequence(SeqAVL). | |
| 1813 | is_sequence([],seq). | |
| 1814 | ||
| 1815 | % check if all elements of the AVL are sequences | |
| 1816 | is_avl_set_of_sequences(AVL,SeqType) :- avl_height(AVL,Height), Height<7, | |
| 1817 | expand_custom_set_to_list(avl_set(AVL),ListOfSeqs), | |
| 1818 | l_is_sequence(ListOfSeqs,SeqType). | |
| 1819 | l_is_sequence([],_). | |
| 1820 | l_is_sequence([S1|T],SeqType) :- is_sequence(S1,SeqType), l_is_sequence(T,SeqType). | |
| 1821 | ||
| 1822 | ||
| 1823 | :- use_module(probsrc(b_global_sets),[b_global_set/1]). | |
| 1824 | maximal_set('INTEGER',_). % integer_set('INTEGER') ? | |
| 1825 | maximal_set(real_set,_). | |
| 1826 | maximal_set(string_set,_). | |
| 1827 | maximal_set(bool_set,_). | |
| 1828 | maximal_set('typeset',_). | |
| 1829 | maximal_set(cartesian_product(A,B),Hyps) :- % SIMP_CPROD_EQUAL_TYPE | |
| 1830 | maximal_set(A,Hyps), maximal_set(B,Hyps). | |
| 1831 | maximal_set(relations(A,B),Hyps) :- % SIMP_TYPE_EQUAL_REL | |
| 1832 | maximal_set(A,Hyps), maximal_set(B,Hyps). | |
| 1833 | maximal_set(set_subtraction(A,B),Hyps) :- % SIMP_SETMINUS_EQUAL_TYPE | |
| 1834 | maximal_set(A,Hyps), check_equal_empty_set(B,Hyps,_). | |
| 1835 | maximal_set(pow_subset(A),Hyps) :- maximal_set(A,Hyps). | |
| 1836 | maximal_set('$'(ID),Hyps) :- is_global_set_id(ID,Hyps). | |
| 1837 | maximal_set(value(avl_set(AVL)),_) :- | |
| 1838 | quick_definitely_maximal_set_avl(AVL). | |
| 1839 | maximal_set(set_extension(A),Hyps) :- maximal_set_extension(A,Hyps). | |
| 1840 | % sorted_set_extension is never maximal | |
| 1841 | maximal_set(comprehension_set(_,truth),_). | |
| 1842 | %maximal_set(X,_) :- print(max_fail(X)),nl,fail. | |
| 1843 | ||
| 1844 | construct_set_extension([],_,Res) :- !, Res=empty_set. | |
| 1845 | construct_set_extension(L,Hyps,Res) :- maximal_set_extension(L,Hyps),!, Res='typeset'. | |
| 1846 | construct_set_extension(L,_,sorted_set_extension(SL)) :- | |
| 1847 | %length(L,Len), format('Construct set_extension ~w~n',[Len]), | |
| 1848 | sort(L,SL). | |
| 1849 | ||
| 1850 | maximal_set_extension([boolean_true|T],_) :- !, member(boolean_false,T). | |
| 1851 | maximal_set_extension([boolean_false|T],_) :- !, member(boolean_true,T). | |
| 1852 | maximal_set_extension(['$'(ID)|T],Hyps) :- | |
| 1853 | is_global_constant_id(ID,Hyps), | |
| 1854 | sort(['$'(ID)|T],Sorted), | |
| 1855 | maplist(is_glob_const_id(Hyps),Sorted), % all elements are global constants | |
| 1856 | lookup_global_constant(ID,fd(_,GlobalSet)), | |
| 1857 | enumerated_set(GlobalSet),b_global_set_cardinality(GlobalSet,Size), | |
| 1858 | length(Sorted,Size). | |
| 1859 | %maximal_set_extension(X,_) :- print(maximal_failed(X)),nl,fail. | |
| 1860 | ||
| 1861 | is_glob_const_id(Hyps,'$'(ID)) :- is_global_constant_id(ID,Hyps). | |
| 1862 | ||
| 1863 | ||
| 1864 | is_global_set_id(ID,Hyps) :- | |
| 1865 | b_global_set(ID), | |
| 1866 | \+ is_hyp_var(ID,Hyps). % global enumerated set visible | |
| 1867 | ||
| 1868 | % often called with 0 or 1 in first position | |
| 1869 | check_leq(I,I,_) :- !. | |
| 1870 | check_leq(if_then_else(Pred,A1,A2),B,Hyp) :- !, | |
| 1871 | push_and_rename_normalized_hyp(Pred,Hyp,Hyp1), | |
| 1872 | (hyps_inconsistent(Hyp1) -> true ; check_leq(A1,B,Hyp1) -> true), | |
| 1873 | push_and_rename_normalized_hyp(negation(Pred),Hyp,Hyp2), | |
| 1874 | (hyps_inconsistent(Hyp2) -> true ; check_leq(A2,B,Hyp2) -> true). | |
| 1875 | check_leq(N1,N2,_) :- number(N1), number(N2), !, N1 =< N2. | |
| 1876 | check_leq(N1,N2,hyp_rec(AVL,_)) :- | |
| 1877 | (avl_fetch(less_equal(N1,N2),AVL) | |
| 1878 | -> true | |
| 1879 | ; avl_fetch(equal(N1,N2),AVL)),!. | |
| 1880 | check_leq(min(List),N2,Hyps) :- !, | |
| 1881 | member(N1,List), check_leq(N1,N2,Hyps),!. | |
| 1882 | check_leq(min_int,N2,Hyps) :- !, % we could look up the value of MININT; but largest possible value is -1 | |
| 1883 | MININT is -1, | |
| 1884 | check_leq(MININT,N2,Hyps). | |
| 1885 | check_leq(N1,max_int,Hyps) :- !, % we could look up the value of MAXINT; but smallest possible value is 1 | |
| 1886 | MAXINT = 1, | |
| 1887 | check_leq(N1,MAXINT,Hyps). | |
| 1888 | check_leq(N1,N2,Hyps) :- | |
| 1889 | rewrite_integer(N2,Hyps,RN2,Hyps2),!, | |
| 1890 | check_leq(N1,RN2,Hyps2). | |
| 1891 | check_leq(add(N1,1),N2,Hyps) :- | |
| 1892 | check_not_equal(N1,N2,Hyps), | |
| 1893 | !, % N1+1 <= N2 if N1 <= N2 & N1 \= N2 ; happens quite often in array traversals | |
| 1894 | check_leq(N1,N2,Hyps). | |
| 1895 | check_leq(N1,minus(N2,1),Hyps) :- % variation of rule above | |
| 1896 | check_not_equal(N1,N2,Hyps), | |
| 1897 | !, % N1 <= N2-1 if N1 <= N2 & N1 \= N2 ; happens in array traversals | |
| 1898 | check_leq(N1,N2,Hyps). | |
| 1899 | check_leq(Nr,X,Hyps) :- | |
| 1900 | \+ number(X), | |
| 1901 | try_get_set_of_possible_values(X,Hyps,SetX,Hyps2), | |
| 1902 | check_all_values_geq_val(SetX,Nr,Hyps2),!. | |
| 1903 | check_leq(Nr,X,Hyps) :- number(Nr), !, | |
| 1904 | check_leq_nr(Nr,X,Hyps). | |
| 1905 | check_leq(N1,N2,Hyps) :- rewrite_integer(N1,Hyps,RN1,Hyps2),!, | |
| 1906 | check_leq(RN1,N2,Hyps2). | |
| 1907 | check_leq(Add,N2,Hyps) :- % A+N1 <= N2 <=> A <= N2-N1 | |
| 1908 | number(N2), | |
| 1909 | add_with_number(Add,A,N1),!, | |
| 1910 | N21 is N2-N1, | |
| 1911 | check_leq(A,N21,Hyps). | |
| 1912 | check_leq(Mul,N2,Hyps) :- % A*N1 <= N2 if A <= N2/N1 if N1>0 and N2 mod N1=0 | |
| 1913 | number(N2), | |
| 1914 | mul_with_number(Mul,Hyps,A,N1), | |
| 1915 | % symmetrical case to check_leq_nr(N1,Mul,Hyps), with N1=-N2 | |
| 1916 | !, | |
| 1917 | ( N1=0 -> check_leq(0,N2,Hyps) | |
| 1918 | ; N1>0 -> N21 is N2 div N1, % A <= 1.5 means we have to have A <= 1; | |
| 1919 | % A <= -1.5 means we have to have A <= -2 -3 div 2 =:= -2 | |
| 1920 | check_leq(A,N21,Hyps) | |
| 1921 | ; cdiv(N2,N1,N21), % A >= 1.5 means we have to have A >= 2 ; cdiv | |
| 1922 | check_leq(N21,A,Hyps) | |
| 1923 | ). | |
| 1924 | check_leq(div(A,N1),N2,Hyps) :- | |
| 1925 | number(N1),number(N2), N1>0, | |
| 1926 | !, | |
| 1927 | (N2=0 -> N12 is N2-1 % A/4 <= 0 <=> A <= 3 | |
| 1928 | ; N2 >= 0 -> N12 is (N2+1)*N1-1 % A/4 <= 10 <=> A <= 49 % A/N1 <= N2 <=> A <= (N1+1)*N2-1 | |
| 1929 | ; N12 is N2*N1 % A/4 <= -10 <=> A <= -40 | |
| 1930 | ), | |
| 1931 | check_leq(A,N12,Hyps). | |
| 1932 | check_leq(div(A1,N1),A2,Hyps) :- number(N1), N1>0, % A/N1 <= A if N1>0 & A>=0 | |
| 1933 | check_equal(A1,A2,Hyps,Hyps1),!, | |
| 1934 | check_leq(0,A1,Hyps1). | |
| 1935 | check_leq(modulo(A1,A2),B,Hyps) :- | |
| 1936 | \+ z_or_tla_minor_mode, % args to mod must be non-negative, modulo is between 0..A2-1 | |
| 1937 | ((number(A2),A21 is A2-1 -> check_leq(A21,B,Hyps) | |
| 1938 | ; B=minus(B1,1) -> check_leq(A2,B1,Hyps) | |
| 1939 | ; check_leq(A2,B,Hyps) | |
| 1940 | ) -> true | |
| 1941 | ; check_leq(A1,B,Hyps)). | |
| 1942 | % TO DO: modulo as RHS | |
| 1943 | check_leq(unary_minus(A),unary_minus(B),Hyps) :- !, % -A <= -B ---> A >= B | |
| 1944 | check_leq(B,A,Hyps). | |
| 1945 | check_leq(X,Nr,Hyps) :- \+ number(X), | |
| 1946 | try_get_set_of_possible_values(X,Hyps,SetX,Hyps2), | |
| 1947 | check_all_values_leq_val(SetX,Nr,Hyps2),!. % cut here; get set of possible values can give multiple solutions | |
| 1948 | check_leq(Minus,N2,Hyps) :- minus_with_number(Minus,N1,Nr), | |
| 1949 | Nr >= 0,!, % N1-Nr <= N2 if N1 <= N2 | |
| 1950 | % Both N1 and N2 are usually not numbers here | |
| 1951 | check_leq(N1,N2,Hyps). | |
| 1952 | check_leq(N1,Add,Hyps) :- | |
| 1953 | add_with_number(Add,N2,Nr),Nr >= 0,!, % N1 <= N2+Nr if N1 <= N2 | |
| 1954 | % Both N1 and N2 are usually not numbers here | |
| 1955 | check_leq(N1,N2,Hyps). | |
| 1956 | check_leq(add(A,B),E,Hyps) :- | |
| 1957 | decompose_floor(E,Hyps,X,Y), % e.g. divide a number E by 2 | |
| 1958 | check_leq(A,X,Hyps), % TO DO: other combinations like A <= 0, B <= Nr; or we could try_get_set_of_possible_values | |
| 1959 | check_leq(B,Y,Hyps). | |
| 1960 | check_leq('$'(X),N2,Hyps) :- | |
| 1961 | avl_fetch_binop_from_hyps('$'(X),less_equal,Hyps,Y,Hyps2), | |
| 1962 | (number(N2),avl_fetch_not_equal('$'(X),Y,Hyps) % as we know X and Y we can use regular avl_fetch | |
| 1963 | -> N21 is N2+1 % we have X<Y in the Hypotheses, we just require that Y <= N2+1 | |
| 1964 | ; N21=N2), | |
| 1965 | check_leq(Y,N21,Hyps2). | |
| 1966 | check_leq(Nr,'$'(X),Hyps) :- | |
| 1967 | ( avl_fetch_equal_from_hyps('$'(X),Hyps,Y,Hyps2), | |
| 1968 | rewrite_local_loop_check(X,check_leq,Y,Hyps2,Hyps3), | |
| 1969 | check_leq(Nr,Y,Hyps3) -> true | |
| 1970 | % ; avl_fetch_binop_from_hyps('$'(X),greater,Hyps,Y,Hyps2), N1 is Nr-1, check_leq(N1,Y,Hyps2) -> true | |
| 1971 | ; avl_fetch_binop_from_hyps('$'(X),greater_equal,Hyps,Y,Hyps2), | |
| 1972 | % note: Nr is not a number, hence probably not useful to check not_equal in Hyps, as we cannot compute Nr-1 | |
| 1973 | check_leq(Nr,Y,Hyps2) | |
| 1974 | -> true | |
| 1975 | ), | |
| 1976 | !. | |
| 1977 | %check_leq(A,B,_H) :- print(check_leq_failed(A,B)),nl, portray_hyps(_H),nl,fail. | |
| 1978 | ||
| 1979 | % decompose an expression E into A and B so that A+B <= E | |
| 1980 | decompose_floor(X,Hyps,A,B) :- get_number(X,Hyps,Nr),!, | |
| 1981 | A is Nr div 2, B=A. % -11 div 2 -> -6, -1 div 2 = -1, 11 div 2 = 5 | |
| 1982 | decompose_floor(add(A,B),_Hyps,A,B). % TO DO: we could try other order | |
| 1983 | decompose_floor(Mul,Hyps,A,A) :- | |
| 1984 | mul_with_number(Mul,Hyps,A,Nr), | |
| 1985 | Nr>=2, % we could divide Nr by 2 | |
| 1986 | (Nr=2 -> true % we have exactly A+A = Mul | |
| 1987 | ; check_leq(0,A,Hyps)). % Note: -10/10 + -10/10 is not <= -10 | |
| 1988 | ||
| 1989 | % ceiling division utility | |
| 1990 | cdiv(N1,N2,Res) :- | |
| 1991 | (N1 mod N2 =:= 0 -> Res is N1//N2 | |
| 1992 | ; Res is (N1 div N2)+1). | |
| 1993 | ||
| 1994 | % Number <= Expression | |
| 1995 | check_leq_nr(N1,Add,Hyps) :- % N1 <= A+N2 <=> N1-N2 <= A | |
| 1996 | add_with_number(Add,A,N2), !, | |
| 1997 | N12 is N1-N2, | |
| 1998 | check_leq(N12,A,Hyps). | |
| 1999 | check_leq_nr(Nr,add(N1,N2),Hyps) :- !, % 0 <= A+B if 0 <= A & 0 <= B | |
| 2000 | % Both N1 and N2 are usually not numbers here | |
| 2001 | cdiv(Nr,2,Nr2), % Note: cdiv(-3,2) = 1, cdiv(3,2)=2 | |
| 2002 | check_leq(Nr2,N1,Hyps), | |
| 2003 | check_leq(Nr2,N2,Hyps). | |
| 2004 | check_leq_nr(N1,minus(N2,B),Hyps) :- % N1 <= N2-B <=> B <= N2-N1 | |
| 2005 | number(N2), !, | |
| 2006 | N21 is N2-N1, | |
| 2007 | check_leq(B,N21,Hyps). | |
| 2008 | check_leq_nr(N1,Mul,Hyps) :- % N1 <= A*N2 if N1/N2 <= A and N2>0 | |
| 2009 | mul_with_number(Mul,Hyps,A,N2), | |
| 2010 | !, | |
| 2011 | ( N2=0 -> check_leq(N1,0,Hyps) | |
| 2012 | ; N2>0 -> cdiv(N1,N2,N12), % cdiv | |
| 2013 | % if 1.5 <= A --> 2 <= A ; if -1.5 <= A --> -1 <= A | |
| 2014 | check_leq(N12,A,Hyps) | |
| 2015 | ; N12 is N1 div N2, | |
| 2016 | % if A <= 1.5 --> A <= 1 ; if -1.5 <= A --> -1 <= A | |
| 2017 | % A <= -1.5 means we have to have A <= -2 -3 div 2 =:= -2 | |
| 2018 | check_leq(A,N12,Hyps) | |
| 2019 | ). | |
| 2020 | check_leq_nr(0,multiplication(A,B),Hyps) :- !, % 0 <= A*B if A and B have same parity | |
| 2021 | (check_leq(0,A,Hyps) -> check_leq(0,B,Hyps) | |
| 2022 | ; check_leq(A,0,Hyps) -> check_leq(B,0,Hyps)). | |
| 2023 | check_leq_nr(N1,div(A,N2),Hyps) :- % N1 <= A/N2 <=> N1*N2 <= A | |
| 2024 | number(N2), N2>0, % TODO: case if N2<0 | |
| 2025 | !, | |
| 2026 | (N1 > 0 -> N12 is N1*N2 % 10 <= A/4 <=> 40 <= A | |
| 2027 | ; N1 = 0 -> N12 is 1-N2 % 0 <= A/4 <=> -3 <= A | |
| 2028 | ; N12 is (N1 - 1)*(N2)+1 % -10 <= A/4 <=> -49 <= A | |
| 2029 | ), | |
| 2030 | check_leq(N12,A,Hyps). | |
| 2031 | check_leq_nr(0,div(A,B),Hyps) :- !, % 0 <= A/B guaranteed if A and B have same parity | |
| 2032 | (check_leq(0,A,Hyps) -> check_leq(0,B,Hyps) % B \= 0 checked by other WD condition | |
| 2033 | ; check_leq(A,0,Hyps) -> check_leq(B,0,Hyps)). % ditto | |
| 2034 | % TODO: other solutions possible, e.g., -1/100 = 1/-100 = 0 | |
| 2035 | check_leq_nr(Nr,'$'(X),Hyps) :- | |
| 2036 | ( avl_fetch_equal_from_hyps('$'(X),Hyps,Y,Hyps2), | |
| 2037 | rewrite_local_loop_check(X,check_leq,Y,Hyps2,Hyps3), | |
| 2038 | check_leq(Nr,Y,Hyps3) -> true | |
| 2039 | % ; avl_fetch_binop_from_hyps('$'(X),greater,Hyps,Y,Hyps2), N1 is Nr-1, check_leq(N1,Y,Hyps2) -> true | |
| 2040 | ; avl_fetch_binop_from_hyps('$'(X),greater_equal,Hyps,Y,Hyps2), | |
| 2041 | (avl_fetch_not_equal('$'(X),Y,Hyps2) % we have X < Y => sufficient to prove N-1 <= Y | |
| 2042 | -> N1 is Nr-1, check_leq(N1,Y,Hyps2) | |
| 2043 | ; check_leq(Nr,Y,Hyps2) | |
| 2044 | ) | |
| 2045 | ), | |
| 2046 | !. | |
| 2047 | check_leq_nr(Nr,modulo(A,B),Hyps) :- \+ z_or_tla_minor_mode, % A and B must be non-negative, modulo is between 0..B-1 | |
| 2048 | (Nr =< 0 -> true % modulo always positive or 0 | |
| 2049 | ; % Nr <= A mod B if Nr <= A and A < B | |
| 2050 | check_leq_nr(Nr,A,Hyps), % Nr <= A | |
| 2051 | check_less(A,B,Hyps)). % and A < B so that modulo does not take effect | |
| 2052 | check_leq_nr(Nr,size(Seq),Hyps) :- check_leq_nr_size(Nr,Seq,Hyps). | |
| 2053 | check_leq_nr(1,power_of(A,_),Hyps) :- check_leq(1,A,Hyps). % Nr <= 1 <= x**y if x >= 1 | |
| 2054 | check_leq_nr(Nr,power_of(A,_),Hyps) :- number(Nr), Nr =< 0, | |
| 2055 | check_leq(0,A,Hyps). % 0 <= x**y if x >= 0 | |
| 2056 | %check_leq_nr(A,B,_H) :- print(check_leq_nr_failed(A,B)),nl,fail. | |
| 2057 | ||
| 2058 | check_less(A,B,Hyps) :- | |
| 2059 | check_leq(A,B,Hyps),!, | |
| 2060 | check_not_equal(A,B,Hyps). | |
| 2061 | ||
| 2062 | :- use_module(probsrc(specfile),[z_or_tla_minor_mode/0]). | |
| 2063 | ||
| 2064 | ||
| 2065 | check_leq_nr_size(Nr,restrict_front(_,RestrN),Hyps) :- !, % X <= size( Seq /|\ N) if X <= N as WD condition implies N : 0..size(Seq) | |
| 2066 | check_leq_nr(Nr,RestrN,Hyps). | |
| 2067 | check_leq_nr_size(1,Seq,Hyps) :- check_is_non_empty_sequence(Seq,Hyps). | |
| 2068 | ||
| 2069 | add_with_number(add(A,B),X,Nr) :- (number(A) -> Nr=A, X=B ; number(B) -> Nr=B, X=A). | |
| 2070 | add_with_number(minus(A,B),A,Nr) :- number(B), Nr is -B. | |
| 2071 | mul_with_number(multiplication(A,B),Hyps,X,Nr) :- | |
| 2072 | (get_number(A,Hyps,Nr) -> X=B ; get_number(B,Hyps,Nr) -> X=A). | |
| 2073 | mul_with_number(unary_minus(A),_Hyps,A,Nr) :- Nr is -1. | |
| 2074 | minus_with_number(add(A,B),A,Nr) :- number(B), Nr is -B. | |
| 2075 | minus_with_number(minus(A,Nr),A,Nr) :- number(Nr). | |
| 2076 | ||
| 2077 | ||
| 2078 | %get_possible_values('$'(X),Hyps,SetX,Hyps2) :- | |
| 2079 | % avl_fetch_binop_from_hyps('$'(X),member,Hyps,SetX,Hyps2). | |
| 2080 | ||
| 2081 | % a few rewrite rules for integer expressions | |
| 2082 | % addition/multiplication is dealt with in other places (and is usually done symbolically) | |
| 2083 | rewrite_integer(size(Seq),Hyps,Size,Hyps2) :- % can happen for sequence POs, like restrict_front,tail | |
| 2084 | compute_card_of_set(Seq,Hyps,Size,Hyps2),!. | |
| 2085 | rewrite_integer(card(Seq),Hyps,Size,Hyps2) :- !, rewrite_card_of_set(Seq,Hyps,Size,Hyps2). | |
| 2086 | rewrite_integer(assertion_expression(_,_,Expr),Hyps,Expr,Hyps). % TO DO: add Predicate to Hyps? | |
| 2087 | % the following may be done by ast_cleanup, but e.g., when applying functions no cleanup is run in l_rename_and_prove_goals | |
| 2088 | rewrite_integer(add(A,B),Hyps,Res,Hyps2) :- compute_integer(A,Hyps,A1,Hyps1), number(A1), | |
| 2089 | (compute_integer(B,Hyps1,B1,Hyps2), number(B1) | |
| 2090 | -> Res is A1+B1 | |
| 2091 | ; A1=0 -> Res = B, Hyps2=Hyps1). | |
| 2092 | rewrite_integer(multiplication(A,B),Hyps,Res,Hyps2) :- compute_integer(A,Hyps,A1,Hyps1), number(A1),!, | |
| 2093 | (A1=0 -> Res=0, Hyps2=Hyps1 | |
| 2094 | ; compute_integer(B,Hyps1,B1,Hyps2), number(B1) | |
| 2095 | -> Res is A1*B1 | |
| 2096 | ; A1=1 -> Res=B, Hyps2=Hyps1). | |
| 2097 | rewrite_integer(multiplication(A,B),Hyps,Res,Hyps2) :- | |
| 2098 | compute_integer(B,Hyps,B1,Hyps2), number(B1), | |
| 2099 | (B1=0 -> Res=0 | |
| 2100 | ; B1=1 -> Res = A). | |
| 2101 | rewrite_integer(unary_minus(A),Hyps,Res,Hyps2) :- compute_integer(A,Hyps,A1,Hyps2), number(A1), | |
| 2102 | Res is -A1. | |
| 2103 | rewrite_integer(minus(A,B),Hyps,Res,Hyps2) :- compute_integer(B,Hyps,B1,Hyps1), number(B1), | |
| 2104 | (compute_integer(A,Hyps1,A1,Hyps2), number(A1) | |
| 2105 | -> Res is A1-B1 | |
| 2106 | ; B1=0 -> Res = A, Hyps2=Hyps1). | |
| 2107 | rewrite_integer(power_of(A,B),Hyps,Res,Hyps2) :- compute_integer(A,Hyps,A1,Hyps1), number(A1), | |
| 2108 | compute_integer(B,Hyps1,B1,Hyps2), number(B1), B1 >=0, | |
| 2109 | % check if not too large: | |
| 2110 | (abs(A1) < 2 -> true | |
| 2111 | ; A1=2 -> B1 =< 64 | |
| 2112 | ; A1 < 4294967296 -> B1 =< 2 | |
| 2113 | ; B1 =< 0 | |
| 2114 | ), | |
| 2115 | Res is A1 ^ B1. | |
| 2116 | rewrite_integer(modulo(A,B),Hyps,Res,Hyps2) :- compute_integer(A,Hyps,A1,Hyps1),number(A1), | |
| 2117 | A1 >= 0, | |
| 2118 | compute_integer(B,Hyps1,B1,Hyps2), number(B1), B1 >0, | |
| 2119 | Res is A1 mod B1. | |
| 2120 | rewrite_integer(div(A,B),Hyps,Res,Hyps2) :- | |
| 2121 | compute_integer(B,Hyps,B1,Hyps1), number(B1), B1 \= 0, | |
| 2122 | (compute_integer(A,Hyps1,A1,Hyps2), number(A1) | |
| 2123 | -> Res is A1 // B1 % Prolog division corresponds to B division | |
| 2124 | ; B1=1 -> Res=A, Hyps2=Hyps1). | |
| 2125 | rewrite_integer(integer(X),Hyps,X,Hyps) :- integer(X), write(wd_unnormalised_integer(X)),nl. % should not happen | |
| 2126 | rewrite_integer(real(X),Hyps,Res,Hyps) :- atom(X), construct_real(X,term(floating(Res))). | |
| 2127 | rewrite_integer(convert_int_floor(RX),Hyps,X,Hyps1) :- | |
| 2128 | compute_integer(RX,Hyps,RX1,Hyps1), number(RX1), X is floor(RX1). %, print(rewr_floor(RX,X)),nl. | |
| 2129 | rewrite_integer(convert_int_ceiling(RX),Hyps,X,Hyps1) :- | |
| 2130 | compute_integer(RX,Hyps,RX1,Hyps1), number(RX1), X is ceiling(RX1). | |
| 2131 | rewrite_integer(convert_real(A),Hyps,RX,Hyps1) :- | |
| 2132 | compute_integer(A,Hyps,A1,Hyps1), integer(A1), RX is float(A1). | |
| 2133 | ||
| 2134 | rewrite_card_of_set(Set,Hyps,Size,Hyps2) :- | |
| 2135 | compute_card_of_set(Set,Hyps,Size,Hyps2),!. | |
| 2136 | rewrite_card_of_set(interval(1,Up),Hyps,Size,Hyps) :- !, % useful if Up is a symbolic expression | |
| 2137 | Size=Up. | |
| 2138 | rewrite_card_of_set(Set,Hyps,Size,Hyps2) :- rewrite_set_expression_exact(Set,Hyps,S2,Hyps1), | |
| 2139 | rewrite_card_of_set(S2,Hyps1,Size,Hyps2). | |
| 2140 | ||
| 2141 | compute_integer(A,Hyps,Res,Hyps) :- get_number(A,Hyps,Nr),!,Res=Nr. | |
| 2142 | compute_integer(A,H,Res,H2) :- rewrite_integer(A,H,Res,H2). | |
| 2143 | ||
| 2144 | get_number(A,_Hyps,Nr) :- number(A),!,Nr=A. | |
| 2145 | get_number('$'(ID),Hyps,Nr) :- Hyps \= nohyps, | |
| 2146 | avl_fetch_equal_from_hyps('$'(ID),Hyps,Nr,_Hyps1), number(Nr). | |
| 2147 | ||
| 2148 | ||
| 2149 | :- use_module(probsrc(b_global_sets), [enumerated_set/1, b_global_set_cardinality/2]). | |
| 2150 | compute_card_of_set(empty_set,Hyps,0,Hyps). | |
| 2151 | compute_card_of_set(empty_sequence,Hyps,0,Hyps). | |
| 2152 | compute_card_of_set(bool_set,Hyps,2,Hyps). | |
| 2153 | compute_card_of_set(interval(L,U),Hyps,Size,Hyps) :- number(L), number(U), Size is U+1-L. | |
| 2154 | compute_card_of_set(value(Val),Hyps,Size,Hyps) :- get_set_val_size(Val,Size). | |
| 2155 | compute_card_of_set(sequence_extension(List),Hyps,Size,Hyps) :- length(List,Size). | |
| 2156 | compute_card_of_set(set_extension([_]),Hyps,Size,Hyps) :- Size=1. % to do check if all elements definitely different | |
| 2157 | compute_card_of_set(sorted_set_extension([_]),Hyps,Size,Hyps) :- Size=1. % ditto | |
| 2158 | compute_card_of_set(rev(A),Hyps,Size,Hyps2) :- !, compute_card_of_set(A,Hyps,Size,Hyps2). | |
| 2159 | compute_card_of_set(front(A),Hyps,Size,Hyps2) :- !, compute_card_of_set(tail(A),Hyps,Size,Hyps2). | |
| 2160 | compute_card_of_set(tail(A),Hyps,Size,Hyps2) :- !, | |
| 2161 | compute_card_of_set(A,Hyps,Size1,Hyps2), number(Size1), Size1>0, | |
| 2162 | Size is Size1-1. | |
| 2163 | compute_card_of_set(concat(A,B),Hyps,Size,Hyps2) :- | |
| 2164 | compute_card_of_set(A,Hyps,SA,Hyps1),!, | |
| 2165 | compute_card_of_set(B,Hyps1,SB,Hyps2), | |
| 2166 | Size is SA+SB. | |
| 2167 | compute_card_of_set('$'(ID),Hyps,Size,Hyps) :- is_enumerated_set(ID,Hyps), | |
| 2168 | !, | |
| 2169 | b_global_set_cardinality(ID,Size). | |
| 2170 | compute_card_of_set('$'(ID),Hyps,Size,Hyps2) :- | |
| 2171 | avl_fetch_equal_from_hyps('$'(ID),Hyps,X2,Hyps1), | |
| 2172 | compute_card_of_set(X2,Hyps1,Size,Hyps2),!. | |
| 2173 | compute_card_of_set('$'(ID),Hyps,Size,Hyps4) :- % e.g., f:1..10 --> BOOL --> card(f) = 10 | |
| 2174 | avl_fetch_binop_from_hyps('$'(ID),member,Hyps,FunctionType,Hyps1), | |
| 2175 | is_partial_function_type(FunctionType,Hyps1,Hyps2), | |
| 2176 | get_exact_domain_of_func_or_rel_type(FunctionType,Hyps2,Dom,Hyps3), | |
| 2177 | compute_card_of_set(Dom,Hyps3,Size,Hyps4). | |
| 2178 | %compute_card_of_set(S,_,_,_) :- print(card_fail(S)),nl,fail. | |
| 2179 | ||
| 2180 | get_set_val_size([],0). | |
| 2181 | get_set_val_size(avl_set(AVL),Size) :- avl_size(AVL,Size). | |
| 2182 | ||
| 2183 | ||
| 2184 | check_all_values_geq_val(intersection(A,B),Nr,Hyps) :- | |
| 2185 | (check_all_values_geq_val(A,Nr,Hyps) -> true ; check_all_values_geq_val(B,Nr,Hyps)). | |
| 2186 | check_all_values_geq_val(union(A,B),Nr,Hyps) :- | |
| 2187 | (check_all_values_geq_val(A,Nr,Hyps) -> check_all_values_geq_val(B,Nr,Hyps)). | |
| 2188 | check_all_values_geq_val(set_subtraction(A,_),Nr,Hyps) :- | |
| 2189 | check_all_values_geq_val(A,Nr,Hyps). | |
| 2190 | check_all_values_geq_val(interval(From,_),Nr,Hyps) :- check_leq(Nr,From,Hyps). | |
| 2191 | check_all_values_geq_val(value(avl_set(AVL)),Nr,Hyps) :- avl_min(AVL,int(Min)), check_leq(Nr,Min,Hyps). | |
| 2192 | check_all_values_geq_val('NATURAL',Nr,Hyps) :- check_leq(Nr,0,Hyps). | |
| 2193 | check_all_values_geq_val('NATURAL1',Nr,Hyps) :- check_leq(Nr,1,Hyps). | |
| 2194 | check_all_values_geq_val(domain(Func),Nr,Hyps) :- | |
| 2195 | get_domain_or_superset(Func,Hyps,DomFunc,Hyps2), | |
| 2196 | check_all_values_geq_val(DomFunc,Nr,Hyps2). | |
| 2197 | check_all_values_geq_val(range(Func),Nr,Hyps) :- | |
| 2198 | get_range_or_superset(Func,Hyps,RanFunc,Hyps2), | |
| 2199 | check_all_values_geq_val(RanFunc,Nr,Hyps2). | |
| 2200 | check_all_values_geq_val(sorted_set_extension(L),Nr,Hyps) :- !, check_all_values_geq_val(set_extension(L),Nr,Hyps). | |
| 2201 | check_all_values_geq_val(set_extension(L),Nr,Hyps) :- | |
| 2202 | (member(Val,L), \+ check_leq(Nr,Val,Hyps) -> fail ; true). | |
| 2203 | check_all_values_geq_val('$'(X),Nr,Hyps) :- | |
| 2204 | avl_fetch_equal_from_hyps('$'(X),Hyps,Y,Hyps2), | |
| 2205 | rewrite_local_loop_check(X,check_all_values_geq_val,Y,Hyps2,Hyps3), | |
| 2206 | check_all_values_geq_val(Y,Nr,Hyps3). | |
| 2207 | %check_all_values_geq_val(A,B,_) :- print(check_all_values_geq_val_failed(A,B)),nl,fail. | |
| 2208 | ||
| 2209 | check_all_values_neq_nr(intersection(A,B),Nr,Hyps) :- | |
| 2210 | (check_all_values_neq_nr(A,Nr,Hyps) -> true ; check_all_values_neq_nr(B,Nr,Hyps)). | |
| 2211 | check_all_values_neq_nr(union(A,B),Nr,Hyps) :- | |
| 2212 | (check_all_values_neq_nr(A,Nr,Hyps) -> check_all_values_neq_nr(B,Nr,Hyps)). | |
| 2213 | check_all_values_neq_nr(set_subtraction(A,_),Nr,Hyps) :- | |
| 2214 | check_all_values_neq_nr(A,Nr,Hyps). | |
| 2215 | check_all_values_neq_nr(interval(From,_),Nr,Hyps) :- number(From),F1 is From-1, check_leq(Nr,F1,Hyps). | |
| 2216 | check_all_values_neq_nr(interval(_,To),Nr,Hyps) :- number(To),T1 is To+1, check_leq(T1,Nr,Hyps). | |
| 2217 | check_all_values_neq_nr('NATURAL',Nr,Hyps) :- check_leq(Nr,-1,Hyps). | |
| 2218 | check_all_values_neq_nr('NATURAL1',Nr,Hyps) :- check_leq(Nr,0,Hyps). | |
| 2219 | check_all_values_neq_nr(sorted_set_extension(L),Nr,Hyps) :- !, check_all_values_neq_nr(set_extension(L),Nr,Hyps). | |
| 2220 | check_all_values_neq_nr(set_extension(L),Nr,Hyps) :- | |
| 2221 | (member(Val,L), \+ check_not_equal(Val,Nr,Hyps) -> fail ; true). | |
| 2222 | check_all_values_neq_nr('$'(X),Nr,Hyps) :- | |
| 2223 | avl_fetch_equal_from_hyps('$'(X),Hyps,Y,Hyps2), | |
| 2224 | rewrite_local_loop_check(X,check_all_values_neq_nr,Y,Hyps2,Hyps3), | |
| 2225 | check_all_values_neq_nr(Y,Nr,Hyps3). | |
| 2226 | %check_all_values_neq_nr(A,B,_) :- print(check_all_values_neq_nr_failed(A,B)),nl,fail. | |
| 2227 | ||
| 2228 | ||
| 2229 | check_all_values_leq_val(intersection(A,B),Nr,Hyps) :- | |
| 2230 | (check_all_values_leq_val(A,Nr,Hyps) -> true ; check_all_values_leq_val(B,Nr,Hyps)). | |
| 2231 | check_all_values_leq_val(union(A,B),Nr,Hyps) :- | |
| 2232 | (check_all_values_leq_val(A,Nr,Hyps) -> check_all_values_leq_val(B,Nr,Hyps)). | |
| 2233 | check_all_values_leq_val(set_subtraction(A,_),Nr,Hyps) :- | |
| 2234 | check_all_values_leq_val(A,Nr,Hyps). | |
| 2235 | check_all_values_leq_val(interval(_,To),Nr,Hyps) :- check_leq(To,Nr,Hyps). | |
| 2236 | check_all_values_leq_val(value(avl_set(AVL)),Nr,Hyps) :- avl_max(AVL,int(Max)), check_leq(Max,Nr,Hyps). | |
| 2237 | check_all_values_leq_val(domain(Func),Nr,Hyps) :- | |
| 2238 | get_domain_or_superset(Func,Hyps,DomFunc,Hyps2), | |
| 2239 | check_all_values_leq_val(DomFunc,Nr,Hyps2). | |
| 2240 | check_all_values_leq_val(range(Func),Nr,Hyps) :- | |
| 2241 | get_range_or_superset(Func,Hyps,RanFunc,Hyps2), | |
| 2242 | check_all_values_leq_val(RanFunc,Nr,Hyps2). | |
| 2243 | check_all_values_leq_val(sorted_set_extension(L),Nr,Hyps) :- !, check_all_values_leq_val(set_extension(L),Nr,Hyps). | |
| 2244 | check_all_values_leq_val(set_extension(L),Nr,Hyps) :- | |
| 2245 | (member(Val,L), \+ check_leq(Val,Nr,Hyps) -> fail ; true). | |
| 2246 | check_all_values_leq_val('$'(X),Nr,Hyps) :- | |
| 2247 | avl_fetch_equal_from_hyps('$'(X),Hyps,Y,Hyps2), | |
| 2248 | rewrite_local_loop_check(X,check_all_values_leq_val,Y,Hyps2,Hyps3), | |
| 2249 | check_all_values_leq_val(Y,Nr,Hyps3). | |
| 2250 | %check_all_values_leq_val(A,B,_) :- print(check_all_values_leq_val(A,B)),nl,fail. | |
| 2251 | ||
| 2252 | % check if two expressions are definitely different | |
| 2253 | % usually called for check_not_equal 0 or empty_set | |
| 2254 | check_not_equal(A,B,Hyp) :- | |
| 2255 | is_explicit_value(A,AV,Hyp), is_explicit_value(B,BV,Hyp), !, AV \= BV. | |
| 2256 | check_not_equal(X,Y,Hyp) :- sym_unify(X,Y,if_then_else(Pred,A1,A2),B),!, | |
| 2257 | push_and_rename_normalized_hyp(Pred,Hyp,Hyp1), | |
| 2258 | (hyps_inconsistent(Hyp1) -> true ; check_not_equal(A1,B,Hyp1) -> true), | |
| 2259 | push_and_rename_normalized_hyp(negation(Pred),Hyp,Hyp2), | |
| 2260 | (hyps_inconsistent(Hyp2) -> true ; check_not_equal(A2,B,Hyp2) -> true). | |
| 2261 | check_not_equal(N1,N2,Hyps) :- | |
| 2262 | avl_fetch_not_equal(N1,N2,Hyps),!. | |
| 2263 | check_not_equal(couple(A1,A2),couple(B1,B2),Hyps) :- !, | |
| 2264 | (check_not_equal(A1,B1,Hyps) -> true ; check_not_equal(A2,B2,Hyps)). | |
| 2265 | check_not_equal(X,B,Hyps) :- number(B), | |
| 2266 | try_get_set_of_possible_values(X,Hyps,SetX,Hyps2), | |
| 2267 | check_all_values_neq_nr(SetX,B,Hyps2),!. | |
| 2268 | % TO DO: compute also things like domain(...) for :wd s:perm(1..10) & x:dom(s) & res = 10/x | |
| 2269 | check_not_equal(X,Y,Hyps) :- sym_unify(X,Y,unary_minus(A),B),number(B),!, BM is -B, | |
| 2270 | check_not_equal(A,BM,Hyps). | |
| 2271 | check_not_equal(X,Y,Hyps) :- sym_unify(X,Y,multiplication(A,B),0),!, % A*B /= 0 if A/=0 & B/=0 | |
| 2272 | check_not_equal(A,0,Hyps),check_not_equal(B,0,Hyps). | |
| 2273 | check_not_equal(X,Y,Hyps) :- sym_unify(X,Y,power_of(A,_),0),!, % A**B /= 0 if A/=0 | |
| 2274 | check_not_equal(A,0,Hyps). | |
| 2275 | check_not_equal(X,Y,Hyps) :- sym_unify(X,Y,Add,B), | |
| 2276 | add_with_number(Add,A,Nr),!, | |
| 2277 | (Nr>0 -> check_leq(B,A,Hyps) % A >= B => A+Nr > B => A+Nr /= B | |
| 2278 | ; Nr=0 -> check_not_equal(A,B,Hyps) | |
| 2279 | ; check_leq(A,B,Hyps) | |
| 2280 | ). | |
| 2281 | check_not_equal(X,Y,Hyps) :- sym_unify(X,Y,A,B),number(B),!, | |
| 2282 | B1 is B+1, | |
| 2283 | (check_leq(B1,A,Hyps) -> true % B < A | |
| 2284 | ; B2 is B-1, | |
| 2285 | check_leq(A,B2,Hyps)). % A < B | |
| 2286 | check_not_equal(XX,YY,Hyps) :- sym_unify(XX,YY,'$'(A),B), | |
| 2287 | avl_fetch_binop_from_hyps('$'(A),less_equal,Hyps,Y,Hyps2), | |
| 2288 | (number(B) -> (B1 is B-1, check_leq(Y,B1,Hyps2) -> true) | |
| 2289 | ; avl_fetch_not_equal('$'(A),Y,Hyps) % we have $(A) < Y => prove Y <= B | |
| 2290 | -> check_leq(Y,B,Hyps2) % we can prove x<y & y<=z => x<z but we cannot yet prove x<=y & y<z => x<z | |
| 2291 | ). | |
| 2292 | check_not_equal(XX,YY,Hyps) :- sym_unify(XX,YY,'$'(A),B), | |
| 2293 | avl_fetch_binop_from_hyps('$'(A),greater_equal,Hyps,Y,Hyps2), | |
| 2294 | (number(B) -> (B1 is B+1, check_leq(B1,Y,Hyps2) -> true) | |
| 2295 | ; avl_fetch_not_equal('$'(A),Y,Hyps) % we have $(A) < Y => prove Y <= B | |
| 2296 | -> check_leq(B,Y,Hyps2) % see comments above | |
| 2297 | ). | |
| 2298 | check_not_equal(A,Empty,Hyp) :- is_empty_set_direct(Empty), !, check_not_empty_set(A,Hyp). | |
| 2299 | check_not_equal(Empty,A,Hyp) :- is_empty_set_direct(Empty), !, check_not_empty_set(A,Hyp). | |
| 2300 | check_not_equal(value(avl_set(A)),value(avl_set(B)),_) :- nonvar(A), nonvar(B),!, % nonvar should always be true | |
| 2301 | \+ equal_avl_tree(A,B). | |
| 2302 | check_not_equal(A,B,Hyps) :- | |
| 2303 | (A=set_extension(LA) -> check_not_equal_set_extension(B,LA,Hyps) | |
| 2304 | ; B=set_extension(LB) -> check_not_equal_set_extension(A,LB,Hyps)),!. | |
| 2305 | check_not_equal(A,B,Hyps) :- | |
| 2306 | (is_interval(A,Hyps,Low,Up) -> check_not_equal_interval(B,lhs,Low,Up,Hyps) | |
| 2307 | ; is_interval(B,Hyps,Low,Up) -> check_not_equal_interval(A,rhs,Low,Up,Hyps)),!. | |
| 2308 | check_not_equal(A,B,Hyps) :- | |
| 2309 | avl_fetch_worthwhile_equal_from_hyps(A,Hyps,Value,Hyps2),!, | |
| 2310 | check_not_equal(Value,B,Hyps2). | |
| 2311 | check_not_equal(A,B,Hyps) :- | |
| 2312 | avl_fetch_worthwhile_equal_from_hyps(B,Hyps,Value,Hyps2),!, | |
| 2313 | check_not_equal(A,Value,Hyps2). | |
| 2314 | %check_not_equal(A,B,Hyps) :- print(check_not_equal_failed(A,B)),nl,portray_hyps(Hyps),nl,fail. | |
| 2315 | ||
| 2316 | check_not_equal_interval(MaxSet,_,_,_,Hyps) :- infinite_integer_set(MaxSet,Hyps). | |
| 2317 | check_not_equal_interval(A,lhs,Low,Up,Hyps) :- is_interval(A,Hyps,LowA,UpA), | |
| 2318 | (check_not_empty_interval(Low,Up,Hyps) -> true ; check_not_empty_interval(LowA,UpA,Hyps)), | |
| 2319 | % if one of the intervals is non-empty then it is sufficient for one bound to be different | |
| 2320 | (check_not_equal(LowA,Low,Hyps) -> true | |
| 2321 | ; check_not_equal(UpA,Up,Hyps) -> true). | |
| 2322 | % TODO: other intervals | |
| 2323 | ||
| 2324 | infinite_integer_set('INTEGER',_). | |
| 2325 | infinite_integer_set('NATURAL',_). | |
| 2326 | infinite_integer_set('NATURAL1',_). | |
| 2327 | ||
| 2328 | check_not_equal_set_extension(set_extension([B|TB]),[A|TA],Hyps) :- (TA=[];TB=[]),!, | |
| 2329 | check_not_equal(A,B,Hyps). % TO DO: we can generalize this treatment to find one element in one set not in the other | |
| 2330 | check_not_equal_set_extension(value(avl_set(AVL)),LA,Hyps) :- length(LA,MaxSizeA), | |
| 2331 | (avl_size(AVL,Sze),Sze>MaxSizeA -> true % AVL has at least one element more | |
| 2332 | ; is_one_element_avl(AVL,B), LA=[A|_], check_not_equal(A,B,Hyps)). | |
| 2333 | ||
| 2334 | avl_fetch_not_equal(N1,N2,hyp_rec(AVL,_)) :- | |
| 2335 | (avl_fetch(not_equal(N1,N2),AVL) -> true | |
| 2336 | ; avl_fetch(not_equal(N2,N1),AVL)). % we do not store both directions for not_equal | |
| 2337 | ||
| 2338 | % unify two variables with other two variables; useful for symmetric rules | |
| 2339 | sym_unify(A,B,A,B). | |
| 2340 | sym_unify(A,B,B,A). | |
| 2341 | ||
| 2342 | % TO DO: get equalities; maybe we should harmonise this for all rules | |
| 2343 | % we could add rules about min_int, max_int | |
| 2344 | ||
| 2345 | ||
| 2346 | % we should call this to check if something is the empty set: | |
| 2347 | % it does equality rewrites, but also calls check_empty_set/3 indirectly | |
| 2348 | check_equal_empty_set(Set,Hyps,PT) :- | |
| 2349 | check_equal(Set,empty_set,Hyps,PT). % will also call this below: | |
| 2350 | ||
| 2351 | is_empty_set_direct(empty_set). | |
| 2352 | is_empty_set_direct(empty_sequence). | |
| 2353 | is_empty_set_direct(value(X)) :- X==[]. | |
| 2354 | ||
| 2355 | check_empty_set(Set,_,empty_set) :- is_empty_set_direct(Set),!. | |
| 2356 | check_empty_set(A,Hyps,hyp) :- avl_fetch_from_hyps(equal(A,empty_set),Hyps),!. | |
| 2357 | check_empty_set(set_subtraction(A,B),Hyp,subset(PT)) :- !, % see SIMP_SETMINUS_EQUAL_EMPTY Rodin proof rule | |
| 2358 | check_is_subset(A,B,Hyp,PT). | |
| 2359 | check_empty_set(intersection(A,B),Hyps,inter_disjoint) :- !, | |
| 2360 | check_disjoint(A,B,Hyps). | |
| 2361 | check_empty_set(union(A,B),Hyps,union_empty(P1,P2)) :- !, % SIMP_BUNION_EQUAL_EMPTY | |
| 2362 | check_equal_empty_set(A,Hyps,P1),!, | |
| 2363 | check_equal_empty_set(B,Hyps,P2). | |
| 2364 | check_empty_set(cartesian_product(A,B),Hyps,cart_empty(PT)) :- !, % SIMP_CPROD_EQUAL_EMPTY | |
| 2365 | (check_equal_empty_set(A,Hyps,PT) -> true ; check_equal_empty_set(B,Hyps,PT)). | |
| 2366 | check_empty_set(pow1_subset(A),Hyps,pow1_empty(PT)) :- !, % SIMP_POW1_EQUAL_EMPTY | |
| 2367 | check_equal_empty_set(A,Hyps,PT). | |
| 2368 | check_empty_set(interval(From,To),Hyps,interval_empty) :- !, % SIMP_UPTO_EQUAL_EMPTY | |
| 2369 | check_less(To,From,Hyps). | |
| 2370 | check_empty_set(domain(A),Hyps,domain_empty(PT)) :- !, % SIMP_DOM_EQUAL_EMPTY | |
| 2371 | check_equal_empty_set(A,Hyps,PT). | |
| 2372 | check_empty_set(range(A),Hyps,range_empty(PT)) :- !, % SIMP_RAN_EQUAL_EMPTY | |
| 2373 | check_equal_empty_set(A,Hyps,PT). | |
| 2374 | check_empty_set(reverse(A),Hyps,reverse_empty(PT)) :- !, % SIMP_CONVERSE_EQUAL_EMPTY (relational inverse) | |
| 2375 | check_equal_empty_set(A,Hyps,PT). | |
| 2376 | check_empty_set(total_relation(A,B),Hyp,trel_empty(PTA,PTB)) :- !, % SIMP_SPECIAL_EQUAL_RELDOM | |
| 2377 | check_not_equal_empty_set(A,Hyp,PTA), check_equal_empty_set(B,Hyp,PTB). | |
| 2378 | check_empty_set(total_function(A,B),Hyp,tfun_empty(PTA,PTB)) :- !, % SIMP_SPECIAL_EQUAL_RELDOM | |
| 2379 | check_not_equal_empty_set(A,Hyp,PTA), check_equal_empty_set(B,Hyp,PTB). | |
| 2380 | check_empty_set(A,Hyps,subset_strict_singleton) :- | |
| 2381 | avl_fetch_binop_from_hyps(A,subset_strict,Hyps,B,_), % A <<: {Single} => A={} | |
| 2382 | singleton_set(B,_). | |
| 2383 | % TODO: add more rules inter(A,Singleton) SIMP_BINTER_SING_EQUAL_EMPTY | |
| 2384 | ||
| 2385 | % we should call this to check if something is not the empty set: | |
| 2386 | % it does equality rewrites, but also calls check_not_empty_set/2 indirectly | |
| 2387 | check_not_equal_empty_set(Set,Hyps,not_equal_empty_set) :- | |
| 2388 | check_not_equal(Set,empty_set,Hyps). | |
| 2389 | ||
| 2390 | check_not_empty_set(A,Hyps) :- avl_fetch_from_hyps(not_equal(A,empty_set),Hyps),!. | |
| 2391 | check_not_empty_set(A,Hyps) :- %Note: size(A) should be changed to card(A) in normalization | |
| 2392 | (CardA = card(A) ; CardA = size(A)), | |
| 2393 | (Op = equal ; Op = greater_equal), | |
| 2394 | avl_fetch_binop_from_hyps(CardA,Op,Hyps,Nr,Hyps2), %Nr \= 0, | |
| 2395 | check_leq(1,Nr,Hyps2),!. % cut here, relevant for test 2043 | |
| 2396 | check_not_empty_set(set_extension([_|_]),_Hyps). | |
| 2397 | check_not_empty_set(sorted_set_extension([_|_]),_Hyps). | |
| 2398 | check_not_empty_set(sequence_extension([_|_]),_Hyps). | |
| 2399 | check_not_empty_set(cartesian_product(A,B),Hyps) :- % SIMP_CPROD_EQUAL_EMPTY | |
| 2400 | (check_not_empty_set(A,Hyps) -> check_not_empty_set(B,Hyps)). | |
| 2401 | check_not_empty_set(interval(A,B),Hyps) :- check_leq(A,B,Hyps). | |
| 2402 | check_not_empty_set(value(avl_set(AVL)),_) :- AVL \= empty. | |
| 2403 | check_not_empty_set(union(A,B),Hyp) :- !, (check_not_empty_set(A,Hyp) -> true ; check_not_empty_set(B,Hyp)). | |
| 2404 | check_not_empty_set(general_union(A),Hyp) :- !, % SIMP_KUNION_EQUAL_EMPTY | |
| 2405 | check_not_subset(A,set_extension([empty_set]),Hyp,_PT). | |
| 2406 | check_not_empty_set(set_subtraction(A,B),Hyp) :- !, % see SIMP_SETMINUS_EQUAL_EMPTY Rodin proof rule | |
| 2407 | check_not_subset(A,B,Hyp,_PT). | |
| 2408 | check_not_empty_set(overwrite(A,B),Hyp) :- !, (check_not_empty_set(A,Hyp) -> true ; check_not_empty_set(B,Hyp)). | |
| 2409 | check_not_empty_set(domain(A),Hyp) :- !, % SIMP_DOM_EQUAL_EMPTY | |
| 2410 | check_not_empty_set(A,Hyp). | |
| 2411 | check_not_empty_set(range(A),Hyp) :- !, % SIMP_RAN_EQUAL_EMPTY | |
| 2412 | check_not_empty_set(A,Hyp). | |
| 2413 | check_not_empty_set(identity(A),Hyp) :- !, check_not_empty_set(A,Hyp). | |
| 2414 | check_not_empty_set(image(R,interval(L,U)),Hyp) :- !, | |
| 2415 | check_not_empty_set(interval(L,U),Hyp), | |
| 2416 | (check_member_of_set(domain(R),L,Hyp,_) -> true | |
| 2417 | ; check_member_of_set(domain(R),U,Hyp,_) | |
| 2418 | ). | |
| 2419 | check_not_empty_set(image(Func,set_extension([S1|_])),Hyp) :- !, | |
| 2420 | check_member_of_set(domain(Func),S1,Hyp,_). | |
| 2421 | check_not_empty_set(reverse(A),Hyp) :- !, % SIMP_CONVERSE_EQUAL_EMPTY (relational inverse) | |
| 2422 | check_not_empty_set(A,Hyp). | |
| 2423 | check_not_empty_set(rev(A),Hyp) :- !, check_not_empty_set(A,Hyp). | |
| 2424 | check_not_empty_set(concat(A,B),Hyp) :- !, (check_not_empty_set(A,Hyp) -> true ; check_not_empty_set(B,Hyp)). | |
| 2425 | check_not_empty_set(bool_set,_Hyp) :- !. | |
| 2426 | check_not_empty_set(float_set,_Hyp) :- !. | |
| 2427 | check_not_empty_set(real_set,_Hyp) :- !. | |
| 2428 | check_not_empty_set(string_set,_Hyp) :- !. | |
| 2429 | check_not_empty_set('NATURAL1',_Hyp) :- !. % SIMP_NATURAL1_EQUAL_EMPTY | |
| 2430 | check_not_empty_set('NATURAL',_Hyp) :- !. % SIMP_NATURAL_EQUAL_EMPTY | |
| 2431 | check_not_empty_set(typeset,_Hyp) :- !. % SIMP_TYPE_EQUAL_EMPTY, all basic sets are non empty in B and Event-B | |
| 2432 | check_not_empty_set(relations(_,_),_Hyp) :- !. % SIMP_SPECIAL_EQUAL_REL | |
| 2433 | check_not_empty_set(total_function(A,B),Hyp) :- !, % SIMP_SPECIAL_EQUAL_RELDOM | |
| 2434 | ( check_equal_empty_set(A,Hyp,_) -> true | |
| 2435 | ; check_not_equal_empty_set(B,Hyp,_) -> true | |
| 2436 | ; check_equal(A,B,Hyp,_)). % implicit proof by case distinction | |
| 2437 | check_not_empty_set(total_relation(A,B),Hyp) :- !, % SIMP_SPECIAL_EQUAL_RELDOM | |
| 2438 | check_not_empty_set(total_function(A,B),Hyp). | |
| 2439 | check_not_empty_set(if_then_else(Pred,A,B),Hyp) :- !, | |
| 2440 | push_and_rename_normalized_hyp(Pred,Hyp,Hyp1), | |
| 2441 | (hyps_inconsistent(Hyp1) -> true ; check_not_empty_set(A,Hyp1) -> true), | |
| 2442 | push_and_rename_normalized_hyp(negation(Pred),Hyp,Hyp2), | |
| 2443 | (hyps_inconsistent(Hyp2) -> true ; check_not_empty_set(B,Hyp2) -> true). | |
| 2444 | check_not_empty_set(Expr,Hyps) :- | |
| 2445 | is_lambda_function_with_domain(Expr,Domain),!, | |
| 2446 | check_not_empty_set(Domain,Hyps). | |
| 2447 | check_not_empty_set('$'(ID),Hyps) :- | |
| 2448 | enumerated_set(ID), | |
| 2449 | \+ is_hyp_var(ID,Hyps),!. % global enumerated set visible | |
| 2450 | check_not_empty_set(Eq,Hyps) :- | |
| 2451 | (Eq='$'(_) ; Eq=interval(_,_)), | |
| 2452 | avl_fetch_equal_from_hyps(Eq,Hyps,Value,Hyps2), | |
| 2453 | rewrite_local_loop_check(Eq,check_not_empty_set,Value,Hyps2,Hyps3), | |
| 2454 | check_not_empty_set(Value,Hyps3),!. | |
| 2455 | check_not_empty_set(Seq,Hyp) :- infer_sequence_type_of_expr(Seq,Hyp,seq1),!. | |
| 2456 | check_not_empty_set(Func,Hyps) :- Func = '$'(_), | |
| 2457 | avl_fetch_binop_from_hyps(Func,member,Hyps,FunctionType,Hyps2), % Func : . --> . | |
| 2458 | check_not_empty_elements(FunctionType,Hyps2),!. | |
| 2459 | check_not_empty_set(function(Func,Args),Hyps) :- | |
| 2460 | (get_range_or_superset(Func,Hyps,Range,Hyps2), | |
| 2461 | check_not_empty_elements(Range,Hyps2) -> !,true | |
| 2462 | ; rewrite_function_application(Func,Args,Hyps,Result,Hyps2), | |
| 2463 | check_not_empty_set(Result,Hyps2)). | |
| 2464 | check_not_empty_set(tail(A),Hyps) :- rewrite_card_of_set(A,Hyps,CardA,Hyps1),!, | |
| 2465 | check_leq(2,CardA,Hyps1). | |
| 2466 | check_not_empty_set(front(A),Hyps) :- rewrite_card_of_set(A,Hyps,CardA,Hyps1),!, | |
| 2467 | check_leq(2,CardA,Hyps1). | |
| 2468 | check_not_empty_set(A,Hyps) :- | |
| 2469 | avl_fetch_binop_from_hyps(A,not_subset_strict,Hyps,B,_), % A <<: {Single} <=> A={} | |
| 2470 | singleton_set(B,_),!. | |
| 2471 | check_not_empty_set(A,Hyps) :- | |
| 2472 | ( Lookup = A, Operator = superset | |
| 2473 | ; | |
| 2474 | (Lookup=domain(A) ; Lookup=range(A)), | |
| 2475 | (Operator = superset ; Operator = equal) | |
| 2476 | ), | |
| 2477 | avl_fetch_binop_from_hyps(Lookup,Operator,Hyps,B,Hyps2), % B /= {} & B <: A => A /= {} | |
| 2478 | rewrite_local_loop_check(A,check_not_empty_set,B,Hyps2,Hyps3), | |
| 2479 | check_not_empty_set(B,Hyps3),!. | |
| 2480 | % TO DO: rule for dom(r)<:A and r not empty implies A not empty; problem: we need lookup for A=dom(r), or dom(r)<:A, could be of form: r:A+->B | |
| 2481 | %check_not_empty_set(A,H) :- print(check_not_empty_set_failed(A)),nl,portray_hyps(H),nl,fail. | |
| 2482 | % TO DO: more rules for sequence operators; infer_sequence_type_of_expr does not look at values of ids | |
| 2483 | ||
| 2484 | ||
| 2485 | % check if elements of a function type or set are guaranteed to be not empty | |
| 2486 | ||
| 2487 | check_not_empty_elements(fin1_subset(_),_). | |
| 2488 | check_not_empty_elements(pow1_subset(_),_). | |
| 2489 | check_not_empty_elements(seq1(_),_). | |
| 2490 | check_not_empty_elements(iseq1(_),_). | |
| 2491 | check_not_empty_elements(perm(A),Hyps) :- check_not_empty_set(A,Hyps). | |
| 2492 | check_not_empty_elements(total_function(A,_),Hyps) :- check_not_empty_set(A,Hyps). | |
| 2493 | check_not_empty_elements(total_injection(A,_),Hyps) :- check_not_empty_set(A,Hyps). | |
| 2494 | check_not_empty_elements(total_surjection(A,B),Hyps) :- | |
| 2495 | (check_not_empty_set(A,Hyps) -> true ; check_not_empty_set(B,Hyps)). | |
| 2496 | check_not_empty_elements(total_bijection(A,B),Hyps) :- | |
| 2497 | (check_not_empty_set(A,Hyps) -> true ; check_not_empty_set(B,Hyps)). | |
| 2498 | check_not_empty_elements(total_relation(A,_),Hyps) :- check_not_empty_set(A,Hyps). | |
| 2499 | check_not_empty_elements(total_surjection_relation(A,_),Hyps) :- check_not_empty_set(A,Hyps). | |
| 2500 | check_not_empty_elements(partial_surjection(_,B),Hyps) :- check_not_empty_set(B,Hyps). | |
| 2501 | check_not_empty_elements(partial_bijection(_,B),Hyps) :- check_not_empty_set(B,Hyps). | |
| 2502 | check_not_empty_elements(surjection_relation(_,B),Hyps) :- check_not_empty_set(B,Hyps). | |
| 2503 | % more cases, set_extension,... | |
| 2504 | ||
| 2505 | :- use_module(probsrc(b_global_sets),[enumerated_set/1]). | |
| 2506 | % check if an expression is definitely finite | |
| 2507 | check_finite(bool_set,_,bool_set) :- !. | |
| 2508 | check_finite(empty_set,_,empty_set) :- !. | |
| 2509 | check_finite(empty_sequence,_,empty_sequence) :- !. | |
| 2510 | check_finite(float_set,_,float_set) :- !. | |
| 2511 | % check_finite(integer_set(X),_,bool_set) :- !. INT, NAT, NAT1 are translated to intervals | |
| 2512 | check_finite(set_extension(_),_,set_extension) :- !. | |
| 2513 | check_finite(sorted_set_extension(_),_,set_extension) :- !. | |
| 2514 | check_finite(sequence_extension(_),_,seq_extension) :- !. | |
| 2515 | check_finite(fin_subset(X),Hyps,fin(PT)) :- !, check_finite(X,Hyps,PT). | |
| 2516 | check_finite(fin1_subset(X),Hyps,fin1(PT)) :- !, check_finite(X,Hyps,PT). | |
| 2517 | check_finite(pow_subset(X),Hyps,pow(PT)) :- !, check_finite(X,Hyps,PT). | |
| 2518 | check_finite(pow1_subset(X),Hyps,pow1(PT)) :- !, check_finite(X,Hyps,PT). | |
| 2519 | check_finite(iseq(X),Hyps,iseq(PT)) :- !, check_finite(X,Hyps,PT). | |
| 2520 | check_finite(iseq1(X),Hyps,iseq1(PT)) :- !, check_finite(X,Hyps,PT). | |
| 2521 | check_finite(mu(Set),Hyps,mu) :- !, has_finite_elements(Set,Hyps). | |
| 2522 | check_finite(perm(X),Hyps,perm(PT)) :- !, check_finite(X,Hyps,PT). | |
| 2523 | check_finite(Set,Hyps,hyp) :- | |
| 2524 | avl_fetch_from_hyps(finite(Set),Hyps),!. | |
| 2525 | check_finite(domain(A),Hyp,dom(PT)) :- !, | |
| 2526 | (check_finite(A,Hyp,PT) -> true ; finite_domain(A,Hyp,PT)). | |
| 2527 | check_finite(range(A),Hyp,ran(PT)) :- !, | |
| 2528 | (check_finite(A,Hyp,PT) -> true ; finite_range(A,Hyp,PT)). | |
| 2529 | check_finite(reverse(A),Hyp,rev(PT)) :- !, check_finite(A,Hyp,PT). | |
| 2530 | check_finite(identity(A),Hyp,id(PT)) :- !,check_finite(A,Hyp,PT). % finite(id(A)) if finite(A) | |
| 2531 | check_finite(function(Func,Args),Hyps,function(PT)) :- !, | |
| 2532 | (get_range_or_superset(Func,Hyps,RanFunc,Hyps2), | |
| 2533 | has_finite_elements(RanFunc,Hyps2) -> PT = finite_elements | |
| 2534 | ; rewrite_function_application(Func,Args,Hyps,Result,Hyps2), | |
| 2535 | check_finite(Result,Hyps2,PT)). | |
| 2536 | check_finite(image(Func,B),Hyp,image(PT)) :- !, | |
| 2537 | (check_finite(Func,Hyp,PT) -> true % finite(Func[.]) <= finite(Func) | |
| 2538 | ; check_finite(B,Hyp,PTB) | |
| 2539 | -> PT = pfun(PTB), check_is_partial_function(Func,Hyp) % finite(Func[B]) <= finite(B) & Func : TD +-> TR | |
| 2540 | ). | |
| 2541 | check_finite(union(A,B),Hyp,union(PTA,PTB)) :- !, (check_finite(A,Hyp,PTA) -> check_finite(B,Hyp,PTB)). | |
| 2542 | check_finite(if_then_else(Pred,A,B),Hyps,if(PTA,PTB)) :- !, | |
| 2543 | push_and_rename_normalized_hyp(Pred,Hyps,Hyps1), | |
| 2544 | (hyps_inconsistent(Hyps1) -> true ; check_finite(A,Hyps1,PTA) -> true), | |
| 2545 | push_and_rename_normalized_hyp(negation(Pred),Hyps,Hyps2), | |
| 2546 | (hyps_inconsistent(Hyps2) -> true ; check_finite(B,Hyps2,PTB) -> true). | |
| 2547 | check_finite(intersection(A,B),Hyps,intersection(D,PT)) :- !, | |
| 2548 | (D=left,check_finite(A,Hyps,PT) -> true ; D=right,check_finite(B,Hyps,PT)). | |
| 2549 | check_finite(cartesian_product(A,B),Hyp,cart(PT)) :- | |
| 2550 | (check_finite(A,Hyp,PT) -> (check_equal_empty_set(A,Hyp,_PT2) -> true ; check_finite(B,Hyp,_PT2)) | |
| 2551 | ; check_equal_empty_set(B,Hyp,PT)). | |
| 2552 | check_finite(Rel,Hyp,rel(PTA,PTB)) :- is_relations_type(Rel,A,B),!, | |
| 2553 | (check_finite(A,Hyp,PTA) -> check_finite(B,Hyp,PTB)). % add other relations | |
| 2554 | check_finite(direct_product(A,B),Hyp,direct_product(PTA,PTB)) :- !, | |
| 2555 | (check_finite(A,Hyp,PTA) -> check_finite(B,Hyp,PTB)). | |
| 2556 | check_finite(parallel_product(A,B),Hyp,parallel_product(PTA,PTB)) :- !, | |
| 2557 | (check_finite(A,Hyp,PTA) -> check_finite(B,Hyp,PTB)). | |
| 2558 | check_finite(overwrite(A,B),Hyp,overwrite(PTA,PTB)) :- !, (check_finite(A,Hyp,PTA) -> check_finite(B,Hyp,PTB)). | |
| 2559 | check_finite(set_subtraction(A,_),Hyps,set_subtraction(PT)) :- !, check_finite(A,Hyps,PT). | |
| 2560 | check_finite(domain_restriction(A,BRel),Hyp,domain_restriction(PT)) :- !, | |
| 2561 | (check_finite(BRel,Hyp,PT) -> true | |
| 2562 | ; check_is_partial_function(BRel,Hyp), check_finite(A,Hyp,PT) | |
| 2563 | ; finite_range(BRel,Hyp,_) -> check_finite(A,Hyp,PT) % finite(a <| brel) if finite(a) & finite(ran(brel)) | |
| 2564 | ). | |
| 2565 | check_finite(domain_subtraction(_,B),Hyp,domain_subtraction(PT)) :- !, check_finite(B,Hyp,PT). | |
| 2566 | check_finite(range_restriction(ARel,B),Hyp,range_restriction(PT)) :- !, | |
| 2567 | (check_finite(ARel,Hyp,PT) -> true | |
| 2568 | ; check_is_injective(ARel,Hyp) -> check_finite(B,Hyp,PT) | |
| 2569 | ; finite_domain(ARel,Hyp,_) -> check_finite(B,Hyp,PT) % finite(arel |> b) if finite(b) & finite(dom(arel)) | |
| 2570 | ). | |
| 2571 | check_finite(image(A,B),Hyp,image(PT)) :- % A[B] is finite if A is finite or if B is finite and A a function | |
| 2572 | (check_finite(A,Hyp,PT) -> true ; check_is_partial_function(A,Hyp), check_finite(B,Hyp,PT)). | |
| 2573 | check_finite(range_subtraction(A,_),Hyp,range_subtraction(PT)) :- check_finite(A,Hyp,PT). | |
| 2574 | check_finite(interval(_,_),_,interval) :- !. | |
| 2575 | check_finite(value(V),_,empty_set_value) :- V==[], !. | |
| 2576 | check_finite(value(X),_,avl_set) :- nonvar(X),X=avl_set(_),!. | |
| 2577 | check_finite('$'(ID),Hyps,finite_type) :- | |
| 2578 | get_hyp_var_type(ID,Hyps,Type), %print(chk_fin(ID,Type)),nl, | |
| 2579 | (is_finite_type_for_wd(Type,Hyps) -> true | |
| 2580 | ; Type = set(couple(DomType,_)), % in principle an infinite relation type | |
| 2581 | is_finite_type_for_wd(DomType,Hyps), % we have something like set(couple(boolean,integer)) | |
| 2582 | % note: we treat this here in addition to the case is_partial_function below, as | |
| 2583 | % sometimes we loose the typing information in the term, e.g., in comprehension_set | |
| 2584 | avl_fetch_equal_from_hyps('$'(ID),Hyps,Func,_), | |
| 2585 | is_lambda_function(Func) % we have a function, it is finite if the domain is finite | |
| 2586 | ),!. | |
| 2587 | check_finite('$'(ID),Hyps,enumerated_set) :- | |
| 2588 | enumerated_set(ID), | |
| 2589 | \+ is_hyp_var(ID,Hyps),!. % global enumerated set visible | |
| 2590 | %check_finite('$'(ID),Hyp,partition) :- | |
| 2591 | % avl_fetch_binop_from_hyps('$'(ID),partition,Hyp,Values,Hyp2), % is now normalized | |
| 2592 | % not_occurs(Values,ID), | |
| 2593 | % l_check_finite(Values,Hyp2),!. | |
| 2594 | check_finite('$'(ID),Hyps,rewrite(Operator,PT)) :- | |
| 2595 | (Operator = equal ; Operator = subset), % for subset_strict we also have subset in Hyp | |
| 2596 | avl_fetch_binop_from_hyps('$'(ID),Operator,Hyps,Set2,Hyps2), | |
| 2597 | not_occurs(Set2,ID), % avoid silly, cyclic rewrites $x -> reverse(reverse($x)) (FunLawsStrings.mch) | |
| 2598 | % however, in SetLawsNatural this prevents proving 2 POs due to SS <: min(SS)..max(SS) | |
| 2599 | rewrite_local_loop_check(ID,check_finite,Set2,Hyps2,Hyps3), | |
| 2600 | check_finite(Set2,Hyps3,PT),!. | |
| 2601 | check_finite(Set,Hyp,finite_elements) :- id_or_record_field(Set), | |
| 2602 | avl_fetch_mem_or_struct(Set,Hyp,Set2,Hyp2), | |
| 2603 | Set2 \= Set, | |
| 2604 | has_finite_elements(Set2,Hyp2). | |
| 2605 | check_finite(Func,Hyp,pfun(PTA,PTB)) :- is_partial_function(Func,A,B),!, | |
| 2606 | % a set of partial functions from A to B is finite if both A and B are finite | |
| 2607 | (check_finite(A,Hyp,PTA) -> check_finite(B,Hyp,PTB)),!. | |
| 2608 | check_finite(Seq,Hyp,seq_type) :- infer_sequence_type_of_expr(Seq,Hyp,_),!. % a sequence is always finite | |
| 2609 | check_finite(comprehension_set(Paras,Body),Hyp,comprehension_set) :- | |
| 2610 | finite_comprehension_set(Paras,Body,Hyp),!. | |
| 2611 | check_finite(struct(rec(Fields)),Hyp,struct) :- maplist(check_finite_field(Hyp),Fields). | |
| 2612 | check_finite(general_union(SetOfSets),Hyp,general_union) :- | |
| 2613 | check_all_finite(SetOfSets,Hyp). | |
| 2614 | check_finite(general_intersection(SetOfSets),Hyp,general_intersection(PT)) :- | |
| 2615 | check_some_finite(SetOfSets,Hyp,PT). | |
| 2616 | % TODO: is_lambda_function_with_domain; improve some proof trees above in style of intersection | |
| 2617 | %check_finite(F,Hyps,_) :- print(check_finite_failed(F)),nl,portray_hyps(Hyps),nl,fail. | |
| 2618 | ||
| 2619 | check_finite_field(Hyp,field(_,Set)) :- check_finite(Set,Hyp,_PT). | |
| 2620 | ||
| 2621 | % we could write a check_all meta_predicate | |
| 2622 | % check if we have a finite set of finite sets; used to determine if union(Sets) is finite | |
| 2623 | check_all_finite(empty_set,_). | |
| 2624 | check_all_finite(empty_sequence,_). | |
| 2625 | check_all_finite(value(avl_set(_AVL)),_Hyp) :- % currently avl_set can only contain finite values for normalisation | |
| 2626 | true. | |
| 2627 | check_all_finite(intersection(A,B),Hyps) :- | |
| 2628 | (check_all_finite(A,Hyps) -> true ; check_all_finite(B,Hyps)). | |
| 2629 | check_all_finite(union(A,B),Hyps) :- | |
| 2630 | (check_all_finite(A,Hyps) -> check_all_finite(B,Hyps)). | |
| 2631 | check_all_finite(sorted_set_extension(L),Hyps) :- !, check_all_finite(set_extension(L),Hyps). | |
| 2632 | check_all_finite(set_extension(L),Hyps) :- | |
| 2633 | (member(Val,L), \+ check_finite(Val,Hyps,_) -> fail % CHECK | |
| 2634 | ; true). | |
| 2635 | check_all_finite('$'(ID),Hyps) :- | |
| 2636 | (Operator = equal ; Operator = subset), % for subset_strict we also have subset in Hyp | |
| 2637 | avl_fetch_binop_from_hyps('$'(ID),Operator,Hyps,Set2,Hyps2), | |
| 2638 | not_occurs(Set2,ID), % avoid silly, cyclic rewrites | |
| 2639 | rewrite_local_loop_check(ID,check_finite,Set2,Hyps2,Hyps3), | |
| 2640 | check_all_finite(Set2,Hyps3),!. | |
| 2641 | check_all_finite(Op,Hyps) :- pow_subset_operator(Op,Set),!, | |
| 2642 | % if Set is finite then all subsets of it are finite and there are only finitely many | |
| 2643 | check_finite(Set,Hyps,_PT). | |
| 2644 | check_all_finite(Op,Hyps) :- iseq_operator(Op,Set),!, | |
| 2645 | % if Set is finite then all injective sequences of it are finite and there are only finitely many | |
| 2646 | check_finite(Set,Hyps,_PT). | |
| 2647 | ||
| 2648 | % check if some set of a set of sets is finite: | |
| 2649 | check_some_finite(sorted_set_extension(L),Hyps,PT) :- !, check_some_finite(set_extension(L),Hyps,PT). | |
| 2650 | check_some_finite(set_extension(L),Hyps,set_extension(PT)) :- | |
| 2651 | (member(Val,L), check_finite(Val,Hyps,PT) -> true). | |
| 2652 | check_some_finite('$'(ID),Hyps,rewrite_id(ID,PT)) :- | |
| 2653 | (Operator = equal ; Operator = superset), % Note: superset not subset as for check_all_finite | |
| 2654 | avl_fetch_binop_from_hyps('$'(ID),Operator,Hyps,Set2,Hyps2), | |
| 2655 | not_occurs(Set2,ID), % avoid silly, cyclic rewrites | |
| 2656 | rewrite_local_loop_check(ID,check_finite,Set2,Hyps2,Hyps3), | |
| 2657 | check_some_finite(Set2,Hyps3,PT),!. | |
| 2658 | %check_some_finite(intersection(A,B),Hyps) :- fail. % Note: the intersection could be empty! | |
| 2659 | check_some_finite(union(A,B),Hyps,union(PT)) :- | |
| 2660 | (check_some_finite(A,Hyps,PT) -> true ; check_some_finite(B,Hyps,PT)). | |
| 2661 | % for pow_subset_operator iseq_operator we would still need to check that the sets are not empty | |
| 2662 | % we cannot currently :prove x<:POW1(INT) & inter({NATURAL}\/x) : FIN(inter({NATURAL}\/x)) | |
| 2663 | ||
| 2664 | ||
| 2665 | pow_subset_operator(fin_subset(X),X). | |
| 2666 | pow_subset_operator(fin1_subset(X),X). | |
| 2667 | pow_subset_operator(pow_subset(X),X). | |
| 2668 | pow_subset_operator(pow1_subset(X),X). | |
| 2669 | iseq_operator(perm(Set),Set). | |
| 2670 | iseq_operator(iseq(Set),Set). | |
| 2671 | iseq_operator(iseq1(Set),Set). | |
| 2672 | ||
| 2673 | % Note: lambdas already treated in is_partial_function check above | |
| 2674 | finite_comprehension_set(Paras,Body,Hyp) :- | |
| 2675 | % first exclude the parameters which can be proven finite on their own | |
| 2676 | % now deal with the rest; we do not pass AllParas as second arg; as all references to excluded IDs is ok (only finitely many values possible) | |
| 2677 | finite_comprehension_set_rest(Paras,Body,Hyp,[],Rest), | |
| 2678 | Rest \= Paras, | |
| 2679 | finite_comprehension_set_rest(Rest,Body,Hyp,[],[]). % do a second pass, e.g., for {x,y|x:{y,y+1} & y:1..2 & x:INTEGER} | |
| 2680 | ||
| 2681 | finite_comprehension_set_rest([],_,_,_,[]). | |
| 2682 | % finite_comprehension_set(['$'(ID)|TID],Body,Hyp) :- finite_type ! | |
| 2683 | finite_comprehension_set_rest([ParaID1|TID],Body,Hyp,UnProven,Rest) :- | |
| 2684 | get_parameter_superset_in_body(ParaExpr,[ParaID1|TID],Body,Values), | |
| 2685 | l_not_occurs(Values,UnProven), % do not rely on not yet finitely proven paras; e.g. for {x,y|x:INTEGER & y=x} | |
| 2686 | match_parameter(ParaExpr,ParaID1), | |
| 2687 | check_finite(Values,Hyp,_PT),!, | |
| 2688 | finite_comprehension_set_rest(TID,Body,Hyp,UnProven,Rest). | |
| 2689 | finite_comprehension_set_rest([ParaID1|TID],Body,Hyp,UnProven,[ParaID1|Rest]) :- | |
| 2690 | finite_comprehension_set_rest(TID,Body,Hyp,[ParaID1|UnProven],Rest). | |
| 2691 | ||
| 2692 | % match_parameter(Expr,ID) -> ID occurs in Expr and finite number of values for Expr implies finite values for ID | |
| 2693 | match_parameter(ParaID,ParaID). | |
| 2694 | match_parameter(couple(ParaID,_),ParaID). % x|->y : Values finite implies finitely many values for x | |
| 2695 | match_parameter(couple(_,ParaID),ParaID). | |
| 2696 | match_parameter(set_extension(Ext),ParaID) :- | |
| 2697 | member(El,Ext), match_parameter(El,ParaID). % {x,..} : Values finite implies finitely many values for x | |
| 2698 | match_parameter(sorted_set_extension(Ext),ParaID) :- match_parameter(set_extension(Ext),ParaID). | |
| 2699 | match_parameter(sequence_extension(Ext),ParaID) :- member(ParaID,Ext). | |
| 2700 | match_parameter(rev(RF),ParaID) :- match_parameter(RF,ParaID). | |
| 2701 | match_parameter(reverse(RF),ParaID) :- match_parameter(RF,ParaID). | |
| 2702 | match_parameter(unary_minus(RF),ParaID) :- match_parameter(RF,ParaID). | |
| 2703 | match_parameter(concat(RF1,RF2),ParaID) :- (match_parameter(RF1,ParaID) -> true ; match_parameter(RF2,ParaID)). | |
| 2704 | match_parameter(union(RF1,RF2),ParaID) :- (match_parameter(RF1,ParaID) -> true ; match_parameter(RF2,ParaID)). | |
| 2705 | match_parameter(overwrite(_,RF),ParaID) :- match_parameter(RF,ParaID). % f <+ RF = (... <<| f ) \/ RF | |
| 2706 | match_parameter(Add,ParaID) :- add_with_number(Add,A,_Number), match_parameter(A,ParaID). | |
| 2707 | match_parameter(Mul,ParaID) :- mul_with_number(Mul,nohyps,A,Number), Number \= 0, match_parameter(A,ParaID). | |
| 2708 | % TO DO: more injective functions where a solution determines the ParaID, identity? direct_product, ... | |
| 2709 | % cartesian_product : only if other set not empty | |
| 2710 | ||
| 2711 | get_parameter_superset_in_body(ParaID,AllParas,Body,Values) :- | |
| 2712 | ( member_in_norm_conjunction(Body,member(ParaID,Values)) | |
| 2713 | ; member_in_norm_conjunction(Body,subset(ParaID,Values)) % there are only finitely many subsets of a finite set | |
| 2714 | ; member_in_norm_conjunction(Body,subset_strict(ParaID,Values)) | |
| 2715 | ; member_in_norm_conjunction(Body,equal(X,Y)), | |
| 2716 | sym_unify(X,Y,ParaID,Value), Values=set_extension([Value]) ), | |
| 2717 | l_not_occurs(Values,AllParas). % as an alternative: check for finite_type of set elements; e.g., detect ID=bool(...) | |
| 2718 | ||
| 2719 | ||
| 2720 | :- use_module(probsrc(bsyntaxtree),[is_set_type/2]). | |
| 2721 | %we suppose this has already failed: finite_domain(A,Hyp) :- check_finite(A,Hyp,PT). | |
| 2722 | finite_domain('$'(ID),Hyps,finite_type) :- | |
| 2723 | get_hyp_var_type(ID,Hyps,Type), | |
| 2724 | is_set_type(Type,couple(DomType,_)), | |
| 2725 | is_finite_type_for_wd(DomType,Hyps),!. | |
| 2726 | finite_domain(domain_restriction(A,Rel),Hyps,domain_restriction(PT)) :- !, | |
| 2727 | (check_finite(A,Hyps,PT) -> true ; finite_domain(Rel,Hyps,PT)). | |
| 2728 | finite_domain(A,Hyp,PT) :- get_domain_or_superset(A,Hyp,DA,Hyp2), check_finite(DA,Hyp2,PT). | |
| 2729 | ||
| 2730 | finite_range('$'(ID),Hyps,finite_type) :- | |
| 2731 | get_hyp_var_type(ID,Hyps,Type), | |
| 2732 | is_set_type(Type,couple(_,RanType)), | |
| 2733 | is_finite_type_for_wd(RanType,Hyps),!. | |
| 2734 | finite_range(A,Hyp,PT) :- get_range_or_superset(A,Hyp,RA,Hyp2),!, check_finite(RA,Hyp2,PT). | |
| 2735 | ||
| 2736 | l_check_finite([],_). | |
| 2737 | l_check_finite([H|T],Hyp) :- (check_finite(H,Hyp,_) -> l_check_finite(T,Hyp)). | |
| 2738 | ||
| 2739 | % is a set containing only finite sets | |
| 2740 | has_finite_elements(fin_subset(_),_) :- !. | |
| 2741 | has_finite_elements(fin1_subset(_),_) :- !. | |
| 2742 | has_finite_elements(pow_subset(X),Hyps) :- !, check_finite(X,Hyps,_). | |
| 2743 | has_finite_elements(pow1_subset(X),Hyps) :- !, check_finite(X,Hyps,_). | |
| 2744 | has_finite_elements(seq(_),_) :- !. % every sequence is always finite (of finite length) | |
| 2745 | has_finite_elements(seq1(_),_) :- !. | |
| 2746 | has_finite_elements(iseq(_),_) :- !. | |
| 2747 | has_finite_elements(iseq1(_),_) :- !. | |
| 2748 | has_finite_elements(perm(_),_) :- !. | |
| 2749 | has_finite_elements(union(A,B),Hyps) :- !, has_finite_elements(A,Hyps), has_finite_elements(B,Hyps). | |
| 2750 | has_finite_elements(intersection(A,B),Hyps) :- !, (has_finite_elements(A,Hyps) -> true ; has_finite_elements(B,Hyps)). | |
| 2751 | has_finite_elements(set_subtraction(A,_),Hyps) :- !, has_finite_elements(A,Hyps). | |
| 2752 | has_finite_elements(sorted_set_extension(L),Hyps) :- !, l_check_finite(L,Hyps). | |
| 2753 | has_finite_elements(set_extension(L),Hyps) :- !, l_check_finite(L,Hyps). | |
| 2754 | has_finite_elements(S,_) :- is_empty_set_direct(S),!. % has no elements | |
| 2755 | has_finite_elements(Func,Hyps) :- is_partial_function(Func,A,B),!, | |
| 2756 | (check_finite(A,Hyps,_) -> true ; is_injective(Func), check_finite(B,Hyps,_)). | |
| 2757 | has_finite_elements(Rel,Hyps) :- is_relations_type(Rel,A,B),!,check_finite(A,Hyps,_),check_finite(B,Hyps,_). | |
| 2758 | %has_finite_elements(F,Hs) :- print(has_finite_elements_failed(F)),nl, portray_hyps(Hs),fail. | |
| 2759 | ||
| 2760 | ||
| 2761 | is_relations_type(relations(A,B),A,B). | |
| 2762 | is_relations_type(surjection_relation(A,B),A,B). | |
| 2763 | is_relations_type(total_relation(A,B),A,B). | |
| 2764 | is_relations_type(total_surjection_relation(A,B),A,B). | |
| 2765 | ||
| 2766 | % TO DO: more rules for functions | |
| 2767 | % ------------------------------ | |
| 2768 | ||
| 2769 | :- use_module(probsrc(avl_tools),[avl_fetch_bin/4]). | |
| 2770 | ||
| 2771 | % fetch member(Ground,Free) construct | |
| 2772 | %avl_fetch_mem(Key, AVL ,Res) :- avl_fetch_bin(Key, member, AVL ,Res). | |
| 2773 | %avl_fetch_equal(Key, AVL ,Res) :- avl_fetch_bin(Key, equal, AVL ,Res). | |
| 2774 | ||
| 2775 | ||
| 2776 | avl_fetch_mem_from_hyps(ID,Hyps,Value,Hyps2) :- | |
| 2777 | avl_fetch_binop_from_hyps(ID,member,Hyps,Value,Hyps2). | |
| 2778 | ||
| 2779 | avl_fetch_worthwhile_mem_from_hyps(ID,Hyps,Value,Hyps2) :- | |
| 2780 | avl_fetch_binop_from_hyps(ID,member,Hyps,Value,Hyps2), | |
| 2781 | \+ maximal_set(Value,Hyps2). | |
| 2782 | ||
| 2783 | avl_fetch_equal_from_hyps(ID,Hyps,Value,Hyps2) :- | |
| 2784 | avl_fetch_binop_from_hyps(ID,equal,Hyps,Value,Hyps2). | |
| 2785 | ||
| 2786 | avl_fetch_worthwhile_equal_from_hyps(ID,Hyps,Value,Hyps2) :- | |
| 2787 | worth_rewriting_with_equal(ID), | |
| 2788 | avl_fetch_binop_from_hyps(ID,equal,Hyps,Value,Hyps2), | |
| 2789 | quick_not_occurs_check(ID,Value). | |
| 2790 | ||
| 2791 | avl_fetch_worthwhile_member_from_hyps(ID,Hyps,Value,Hyps2) :- | |
| 2792 | worth_rewriting_with_equal(ID), | |
| 2793 | avl_fetch_binop_from_hyps(ID,member,Hyps,Value,Hyps2). | |
| 2794 | ||
| 2795 | % fetch member predicate or indirect member via record fields | |
| 2796 | avl_fetch_mem_or_struct(Func,Hyps,Function,Hyps1) :- | |
| 2797 | get_type_from_hyps(Func,Hyps,Function,Hyps1). | |
| 2798 | avl_fetch_mem_or_struct(record_field(Rec,Field),Hyps,FieldType,Hyps2) :- | |
| 2799 | get_record_type_fields(Rec,Fields,Hyps,Hyps2), | |
| 2800 | (member(field(Field,FieldType),Fields) -> true). | |
| 2801 | ||
| 2802 | % find record type and extract fields for a given expression | |
| 2803 | get_record_type_fields(function(Func,_),Fields,Hyps,Hyps2) :- | |
| 2804 | get_range_or_superset(Func,Hyps,Range,Hyps1), | |
| 2805 | check_equal_pattern(Range,struct(rec(Fields)),Hyps1,Hyps2). | |
| 2806 | get_record_type_fields(Rec,Fields,Hyps,Hyps2) :- | |
| 2807 | get_type_from_hyps(Rec,Hyps,RecType,Hyps1), | |
| 2808 | check_equal_pattern(RecType,struct(rec(Fields)),Hyps1,Hyps2). | |
| 2809 | ||
| 2810 | % get type from hyps x:XType or x:ran(F) with F : A->B | |
| 2811 | get_type_from_hyps(X,Hyps,XType,Hyps2) :- | |
| 2812 | avl_fetch_mem_from_hyps(X,Hyps,XSet,Hyps1), | |
| 2813 | get_type2(XSet,Hyps1,XType,Hyps2). | |
| 2814 | get_type_from_hyps(function(Func2,_),Hyps,Range,Hyps2) :- | |
| 2815 | % f : _ +-> ( _ >-> _ ) => f(_) : _ >-> _ | |
| 2816 | get_range_or_superset(Func2,Hyps,Range,Hyps2). | |
| 2817 | get_type_from_hyps(second_of_pair(X),Hyps,Type,Hyps2) :- %prj2 | |
| 2818 | get_type_from_hyps(X,Hyps,XType,Hyps1), | |
| 2819 | check_equal_pattern(XType,cartesian_product(_,Type),Hyps1,Hyps2). | |
| 2820 | get_type_from_hyps(first_of_pair(X),Hyps,Type,Hyps2) :- %prj1 | |
| 2821 | get_type_from_hyps(X,Hyps,XType,Hyps1), | |
| 2822 | check_equal_pattern(XType,cartesian_product(Type,_),Hyps1,Hyps2). | |
| 2823 | get_type_from_hyps(assertion_expression(_,_,X),Hyps,XType,Hyps1) :- | |
| 2824 | get_type_from_hyps(X,Hyps,XType,Hyps1). | |
| 2825 | ||
| 2826 | get_type2(domain(Func),Hyps,XType,Hyps2) :- !, | |
| 2827 | get_domain_or_superset(Func,Hyps,XType,Hyps2). | |
| 2828 | get_type2(range(Func),Hyps,XType,Hyps2) :- !, | |
| 2829 | get_range_or_superset(Func,Hyps,XType,Hyps2). | |
| 2830 | get_type2(Type,Hyps,Type,Hyps). | |
| 2831 | ||
| 2832 | id_or_record_field('$'(_)). | |
| 2833 | id_or_record_field(record_field(_,_)). | |
| 2834 | ||
| 2835 | % perform occurs check if first arg is an identifier: | |
| 2836 | quick_not_occurs_check('$'(ID),Value) :- !, not_occurs(Value,ID). | |
| 2837 | quick_not_occurs_check(_,_). | |
| 2838 | ||
| 2839 | % worth rewriting with equality hyps | |
| 2840 | worth_rewriting_with_equal('$'(_)). | |
| 2841 | worth_rewriting_with_equal(record_field('$'(_),_)). | |
| 2842 | worth_rewriting_with_equal(couple(_,_)). | |
| 2843 | worth_rewriting_with_equal(size(_)). | |
| 2844 | worth_rewriting_with_equal(card(_)). | |
| 2845 | worth_rewriting_with_equal(function(_,_)). | |
| 2846 | ||
| 2847 | % utility to fetch fully ground term from hyp avl | |
| 2848 | avl_fetch_from_hyps(Term,hyp_rec(AVL,_)) :- avl_fetch(Term,AVL). | |
| 2849 | ||
| 2850 | % a version without loop check; can be used if processing is finished afterwards | |
| 2851 | avl_fetch_binop_from_hyps_no_loop_check(ID,BinOp,hyp_rec(AVL,_),Value) :- | |
| 2852 | avl_fetch_bin(ID,BinOp,AVL,Value). | |
| 2853 | ||
| 2854 | % lookup a hypothesis ID BinOp Value in logarithmic time; ID and BinOp must be known | |
| 2855 | avl_fetch_binop_from_hyps(ID,BinOp,hyp_rec(AVL,HInfos),Value,hyp_rec(AVL,HInfos2)) :- | |
| 2856 | avl_fetch_bin(ID,BinOp,AVL,Value), | |
| 2857 | (avl_fetch(prevent_cycle_count,HInfos,CycleCount) % avoid cycles x=y, y=x | |
| 2858 | -> (CycleCount < 5 -> true ; % print(prevented_cycle(ID,CycleCount)),nl, | |
| 2859 | % in test 2018: :wd target = [2,1,1,2,1] & n=size(target) & i:1..n & target(i)=res requires cycle count < 5 | |
| 2860 | !, fail), | |
| 2861 | C1 is CycleCount+1 | |
| 2862 | ; C1 is 1 | |
| 2863 | ), | |
| 2864 | avl_store(prevent_cycle_count,HInfos,C1,HInfos2). | |
| 2865 | % detect local loops; should not be used where Hyps are passed to unrelated goals or one has to reset_local_loop_check | |
| 2866 | rewrite_local_loop_check(_,_,Value,HI,HI1) :- useful_value(Value),!,HI1=HI. | |
| 2867 | rewrite_local_loop_check(Term,ProverPredicate,_,Hyps,_) :- var(Hyps),!, | |
| 2868 | add_internal_error('Var hyps: ',rewrite_local_loop_check(Term,ProverPredicate,_,Hyps,_)),fail. | |
| 2869 | rewrite_local_loop_check(Term,ProverPredicate,_,hyp_rec(AVL,HInfos),hyp_rec(AVL,HInfos1)) :- !, | |
| 2870 | (Term='$'(ID) -> true ; ID=Term), | |
| 2871 | %(avl_fetch(rewritten(Term,ProverPredicate),HInfos) -> print(loop(Term,ProverPredicate)),nl,fail ; true), | |
| 2872 | \+ avl_fetch(rewritten(ID,ProverPredicate),HInfos), | |
| 2873 | avl_store(rewritten(ID,ProverPredicate),HInfos,true,HInfos1). | |
| 2874 | % :wd a : 1 .. sz --> INTEGER & sz=5 & p : perm(dom(a)) & i : 1 .. sz - 1 & res= p(i) % sz rewritten multiple times | |
| 2875 | % :wd f: BOOL --> 1..10 & g : 0..20 --> BOOL & bb:BOOL & (f;g)(bb)=res | |
| 2876 | ||
| 2877 | %reset_local_loop_check() | |
| 2878 | ||
| 2879 | % values where there is no risk of looping when rewriting to: | |
| 2880 | useful_value(Value) :- number(Value). | |
| 2881 | useful_value(interval(A,B)) :- number(A), number(B). | |
| 2882 | useful_value(value(_)). | |
| 2883 | ||
| 2884 | ||
| 2885 | % rename and prove a list of goals | |
| 2886 | l_rename_and_prove_goals([],_,_,[]). | |
| 2887 | l_rename_and_prove_goals([H|T],Subst,Hyps,[PTH|PTT]) :- | |
| 2888 | rename_norm_term(H,Subst,RH),!, | |
| 2889 | prove_po(RH,Hyps,PTH),!, % TO DO: use version of prove_po that does not print info | |
| 2890 | l_rename_and_prove_goals(T,Subst,Hyps,PTT). | |
| 2891 | ||
| 2892 | ||
| 2893 | % small utility for sanity checking | |
| 2894 | check_integer(A,PP) :- not_integer(A),!, add_error(PP,'Not an integer: ',A),fail. | |
| 2895 | check_integer(_,_). | |
| 2896 | not_integer(empty_set). | |
| 2897 | not_integer(empty_sequence). | |
| 2898 | not_integer(interval(_,_)). | |
| 2899 | not_integer(couple(_,_)). | |
| 2900 | not_integer(union(_,_)). | |
| 2901 | not_integer(intersection(_,_)). | |
| 2902 | not_integer(domain(_)). | |
| 2903 | not_integer(range(_)). | |
| 2904 | % TO DO: extend | |
| 2905 | ||
| 2906 | ||
| 2907 | % ---------------- | |
| 2908 | ||
| 2909 | % small REPL to inspect hyps | |
| 2910 | :- public hyp_repl/1. | |
| 2911 | hyp_repl(Hyps) :- hyp_repl_prompt(Hyps),read(Term), !, hyp_repl(Term,Hyps). | |
| 2912 | hyp_repl(_). | |
| 2913 | ||
| 2914 | hyp_repl(end_of_file,_). | |
| 2915 | hyp_repl(quit,_). | |
| 2916 | hyp_repl(exit,_). | |
| 2917 | hyp_repl(help,Hyps) :- write('Use quit to exit, print to portray_hyps, or type an identifier to lookup in hyps'),nl, | |
| 2918 | hyp_repl(Hyps). | |
| 2919 | hyp_repl(print,Hyps) :- portray_hyps(Hyps), hyp_repl(Hyps). | |
| 2920 | hyp_repl(ID,Hyps) :- avl_fetch_equal_from_hyps($(ID),Hyps,Value,_), | |
| 2921 | format('Value for ~w:~n ~w~n',[ID,Value]), | |
| 2922 | hyp_repl(Hyps). | |
| 2923 | ||
| 2924 | hyp_repl_prompt(hyp_rec(AVL,HInfos)) :- | |
| 2925 | avl_size(AVL,Size), | |
| 2926 | avl_size(HInfos,ISize),!, | |
| 2927 | format('hyp_rec(#~w,#~w) >>>',[Size,ISize]). | |
| 2928 | hyp_repl_prompt(_) :- write('ILLEGAL HYP_REC >>>'). |