| 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 >>>'). |