1 | % Heinrich Heine Universitaet Duesseldorf | |
2 | % (c) 2023-2024 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, | |
3 | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) | |
4 | ||
5 | :- module(b2setlog, | |
6 | [bexpr2setlog/4, | |
7 | bpred2setlog/3, | |
8 | solve_pred_with_setlog/3, | |
9 | prove_using_setlog/5 | |
10 | ]). | |
11 | ||
12 | :- use_module(probsrc(module_information)). | |
13 | :- module_info(group,setlog). | |
14 | :- module_info(description,'This module provides a translation from B to Setlog'). | |
15 | ||
16 | :- use_module(library(lists),[maplist/2, maplist/3, include/3, exclude/3]). | |
17 | :- use_module(probsrc(error_manager)). | |
18 | :- use_module(probsrc(preferences), [get_preference/2]). | |
19 | :- use_module(probsrc(debug)). | |
20 | :- use_module(probsrc(bsyntaxtree), [same_id/3, conjunct_predicates/2, create_negation/2]). | |
21 | ||
22 | % Translating expressions to setlog | |
23 | % b2setlog(BAST, Environment, SetLogTranslation, ResultVariable) | |
24 | bexpr2setlog(b(E,_Type,_I),Env,SetLogConstr,Res) :- b2e(E,Env,C,R),!, SetLogConstr=C,Res=R. | |
25 | bexpr2setlog(TE,Env,_,_) :- add_translation_error(Env,'Cannot convert B expression to setlog:',TE),fail. | |
26 | ||
27 | ||
28 | b2e(UnOP,Env,SetLogConstr,Res) :- % Res is a fresh existential variable | |
29 | un_op(UnOP,A,SetLogOperator),!, | |
30 | bexpr2setlog(A,Env,CA,RA), | |
31 | SLOG =.. [SetLogOperator,RA,Res], | |
32 | sconjoin(CA,SLOG,SetLogConstr). | |
33 | b2e(BOP,Env,SetLogConstr,Res) :- % ditto | |
34 | bin_op(BOP,A,B,SetLogOperator),!, | |
35 | bexpr2setlog(A,Env,CA,RA), bexpr2setlog(B,Env,CB,RB), | |
36 | SLOG =.. [SetLogOperator,RA,RB,Res], | |
37 | sconj([CA,CB,SLOG],SetLogConstr). | |
38 | b2e(UNOP,Env,SetLogConstr,Res) :- % ditto | |
39 | arith_un_op(UNOP,A,SetLogOperator),!, | |
40 | barithexpr2setlog(A,Env,CA,RA), | |
41 | SLOG =.. [SetLogOperator,RA], | |
42 | sconj([CA,'is'(Res,SLOG)],SetLogConstr). | |
43 | b2e(BOP,Env,SetLogConstr,Res) :- % ditto | |
44 | arith_bin_op(BOP,A,B,SetLogOperator),!, | |
45 | barithexpr2setlog(A,Env,CA,RA), barithexpr2setlog(B,Env,CB,RB), | |
46 | SLOG =.. [SetLogOperator,RA,RB], | |
47 | sconj([CA,CB,'is'(Res,SLOG)],SetLogConstr). | |
48 | b2e(identifier(ID),Env,true,PrologVar) :- % var is not fresh and cannot be freely unified | |
49 | lookup_identifier(Env,ID,PrologVar). % could also be global_set or global constant | |
50 | b2e(integer(I),_,true,I). | |
51 | b2e(empty_set,_,true,'{}'). | |
52 | b2e(string(S),_,true,string(S)). | |
53 | b2e(boolean_false,_,true,pred_false). | |
54 | b2e(boolean_true,_,true,pred_true). | |
55 | b2e(max_int,_,true,MaxInt) :- | |
56 | get_preference(maxint, MaxInt). | |
57 | b2e(min_int,_,true,MinInt) :- | |
58 | get_preference(minint, MinInt). | |
59 | b2e(bool_set,Env,Constr,R) :- | |
60 | b2sext([b(boolean_false,boolean,[]), | |
61 | b(boolean_true, boolean,[])],Env,Constr,R). | |
62 | % setlog set representations: int/2: interval, cp/2: cartesian_product, List of length 2: couple | |
63 | b2e(cartesian_product(A,B),Env,Constr,R) :- | |
64 | bexpr2setlog(A,Env,CA,RA),bexpr2setlog(B,Env,CB,RB), | |
65 | sconjoin(CA,CB,Constr), R=cp(RA,RB). | |
66 | b2e(interval(A,B),Env,Constr,R) :- | |
67 | bexpr2setlog(A,Env,CA,RA),bexpr2setlog(B,Env,CB,RB), sconjoin(CA,CB,Constr), R=int(RA,RB). | |
68 | b2e(couple(A,B),Env,Constr,R) :- bexpr2setlog(A,Env,CA,RA),bexpr2setlog(B,Env,CB,RB), | |
69 | sconjoin(CA,CB,Constr),R=[RA,RB]. | |
70 | %b2e(convert_bool(A),Env,Constr,R) :- bpred2setlog(A,Env,CA),sconjoin(CA,bool(A,R),Constr). | |
71 | b2e(first_projection(A),Env,Constr,R) :- bexpr2setlog(A,Env,CA,RA),sconjoin(CA,RA=[R,_],Constr). % existential Prolog variable could be problem inside negation | |
72 | b2e(second_projection(A),Env,Constr,R) :- bexpr2setlog(A,Env,CA,RA),sconjoin(CA,RA=[_,R],Constr). | |
73 | b2e(set_extension(L),Env,Constr,R) :- b2sext(L,Env,Constr,R). | |
74 | b2e(value(Val),Env,Constr,R) :- b2v(Val,Env,Constr,R). | |
75 | b2e(comprehension_set(Ids,Body),Env,true,Res) :- | |
76 | Ids=[ID], % TODO: support multiple ids | |
77 | extract_membership(Body,ID,Env,MemberConstr,RestBody), | |
78 | Res = ris(MemberConstr,FilterConstr,Pattern), % intensional setlog set | |
79 | bexpr2setlog(ID,Env,CA,Pattern), | |
80 | bpred2setlog(RestBody,Env,CB), | |
81 | sconjoin(CA,CB,FilterConstr). | |
82 | b2e(pow_subset(BSet),Env, Constr, GIS) :- | |
83 | GIS = '{}'(':'(X,subset(X,SET))), | |
84 | bexpr2setlog(BSet,Env,Constr,SET). | |
85 | % TODO: pow1_subset | |
86 | ||
87 | :- use_module(probsrc(b_global_sets),[lookup_global_constant/2, b_global_set/1]). | |
88 | lookup_identifier(Var,ID,Value) :- (var(Var) ; Var==[]), !, | |
89 | (lookup_global_constant(ID,Val) -> b2v(Val,[],true,Value) % TODO: remove Env and Constr from b2v pred | |
90 | ; b_global_set(ID) -> b2v(global_set(ID),[],true,Value) | |
91 | ; Var = [bind(ID,Value)|_]). % add fresh value to environment, this var is not fresh and cannot be freely unified | |
92 | lookup_identifier([bind(ID1,Val1)|T],ID,Value) :- | |
93 | (ID=ID1 -> Value=Val1 % identifier already exists in environment | |
94 | ; lookup_identifier(T,ID,Value)). | |
95 | ||
96 | % extract membership constraints for Setlog quantifiers and intensional sets | |
97 | extract_membership(b(member(TID1,Set),pred,_),TID2,Env,Constr,Rest) :- | |
98 | same_id(TID1,TID2,_), Rest=b(truth,pred,[]), | |
99 | b2p(member(TID1,Set),Env,Constr), | |
100 | Constr = in(_,_). % just a simple in constraint; TODO: maybe perform type inference | |
101 | extract_membership(b(conjunct(LHS,RHS),pred,_),TID,Env,Constr,Rest) :- | |
102 | (extract_membership(LHS,TID,Env,Constr,LRest) | |
103 | -> conjunct_predicates([LRest,RHS],Rest) | |
104 | ; extract_membership(RHS,TID,Env,Constr,RRest), | |
105 | conjunct_predicates([LHS,RRest],Rest) | |
106 | ). | |
107 | ||
108 | :- use_module(probsrc(custom_explicit_sets),[expand_custom_set_to_list/4]). | |
109 | % translation of B values to setlog | |
110 | b2v(Val,Env,_,_) :- var(Val),!, | |
111 | add_translation_error(Env,'Cannot convert compiled B value variable to setlog:',Val),fail. | |
112 | b2v(pred_false,_,true,pred_false). | |
113 | b2v(pred_true,_,true,pred_true). | |
114 | b2v(int(I),_,true,I). | |
115 | b2v(string(S),_,true,string(S)). | |
116 | b2v(fd(Nr,Set),_,true,SetlogTerm) :- translate_global_fd_value(Nr,Set,SetlogTerm). | |
117 | b2v([],Env,C,R) :- b2e(empty_set,Env,C,R). | |
118 | b2v(couple(A,B),Env,Constr,R) :- b2v(A,Env,CA,RA),b2v(B,Env,CB,RB), | |
119 | sconjoin(CA,CB,Constr),R=[RA,RB]. | |
120 | b2v(avl_set(A),Env,Constr,R) :- | |
121 | expand_custom_set_to_list(avl_set(A),List,_,b2v), | |
122 | b2vlist(List,Env,Constr,R). | |
123 | b2v(global_set(A),Env,Constr,R) :- | |
124 | expand_custom_set_to_list(global_set(A),List,_,b2v), % for deferred sets this will use the scope of ProB | |
125 | b2vlist(List,Env,Constr,R). | |
126 | b2v(Val,Env,_,_) :- print(Val),nl, | |
127 | add_translation_error(Env,'Cannot convert compiled B value to setlog:',Val), fail. | |
128 | ||
129 | translate_global_fd_value(Nr,Set,fd(Nr,Set)). % or should we use numbers? | |
130 | ||
131 | % converting list of B values to setlog | |
132 | b2vlist([],Env,Constr,Res) :- !, b2e(empty_set,Env,Constr,Res). | |
133 | b2vlist([A],Env,Constr,Res) :- !, Res = '{}'(RA), b2v(A,Env,Constr,RA). | |
134 | b2vlist([A|T],Env,Constr,Res) :- b2v(A,Env,CA,RA), | |
135 | Res = '{}'(RA/RT), % Setlog {RA/RT} | |
136 | b2vlist(T,Env,CT,RT), | |
137 | sconjoin(CA,CT,Constr). | |
138 | ||
139 | % translation for arithmetic expressions; avoid creating nested is/2 if possible | |
140 | ||
141 | barithexpr2setlog(b(E,_T,_I),Env,SetLogConstr,Res) :- b2arithe(E,Env,C,R),!, SetLogConstr=C,Res=R. | |
142 | barithexpr2setlog(TE,Env,_,_) :- | |
143 | add_translation_error(Env,'Cannot convert B arithmetic expression to setlog:',TE),fail. | |
144 | ||
145 | b2arithe(integer(I),_,true,I) :- !. | |
146 | b2arithe(UNOP,Env,SetLogConstr,SLOG) :- % ditto | |
147 | arith_un_op(UNOP,A,SetLogOperator),!, | |
148 | barithexpr2setlog(A,Env,SetLogConstr,RA), | |
149 | SLOG =.. [SetLogOperator,RA]. | |
150 | b2arithe(BOP,Env,SetLogConstr,SLOG) :- % ditto | |
151 | arith_bin_op(BOP,A,B,SetLogOperator),!, | |
152 | barithexpr2setlog(A,Env,CA,RA), barithexpr2setlog(B,Env,CB,RB), | |
153 | SLOG =.. [SetLogOperator,RA,RB], | |
154 | sconj([CA,CB],SetLogConstr). | |
155 | b2arithe(BExpr,Env,SetLogConstr,Res) :- b2e(BExpr,Env,SetLogConstr,Res). | |
156 | ||
157 | % binary B operators mapped to Setlog ternary predicates: | |
158 | bin_op(union(A,B),A,B,un). | |
159 | bin_op(intersection(A,B),A,B,inters). | |
160 | bin_op(set_subtraction(A,B),A,B,diff). | |
161 | bin_op(function(A,B),A,B,apply). | |
162 | bin_op(rel_composition(A,B),A,B,comp). | |
163 | bin_op(image(A,B),A,B,rimg). | |
164 | bin_op(domain_restriction(A,B),A,B,dres). | |
165 | bin_op(domain_subtraction(A,B),A,B,dares). | |
166 | bin_op(range_restriction(A,B),A,B,rres). | |
167 | bin_op(range_subtraction(A,B),A,B,rares). | |
168 | bin_op(overwrite(A,B),A,B,oplus). | |
169 | ||
170 | ||
171 | % TODO: use disjointness disj, ndisj | |
172 | % Other candidates: symmetric difference sdiff, composition partial fun: comppf, and dompf, drespf | |
173 | ||
174 | % unary B operators mapped to Setlog binary predicates: | |
175 | un_op(card(A),A,size). | |
176 | un_op(domain(A),A,dom). | |
177 | un_op(id(A),A,id). | |
178 | un_op(max(A),A,smax). | |
179 | un_op(min(A),A,smin). | |
180 | un_op(range(A),A,ran). | |
181 | un_op(reverse(A),A,inv). | |
182 | ||
183 | % unary B arithmetic operators mapped to Setlog is call: | |
184 | arith_un_op(unary_minus(A),A,'-'). | |
185 | ||
186 | % binary B arithmetic operators mapped to Setlog is call: | |
187 | arith_bin_op(add(A,B),A,B,'+'). | |
188 | arith_bin_op(div(A,B),A,B,'div'). | |
189 | arith_bin_op(minus(A,B),A,B,'-'). | |
190 | arith_bin_op(modulo(A,B),A,B,'mod'). | |
191 | arith_bin_op(multiplication(A,B),A,B,'*'). | |
192 | arith_bin_op(power_of(A,B),A,B,'**'). %% Not sure if this works | |
193 | ||
194 | % unsupported: closure, closure1, iterate, union, inter, UNION, INTER, {x | x>2 & x<3}, !x.(x>2 => x>1) | |
195 | % can we support less_real, ... | |
196 | ||
197 | % translate set_extensions | |
198 | b2sext([],Env,Constr,Res) :- !, b2e(empty_set,Env,Constr,Res). | |
199 | b2sext([A],Env,Constr,Res) :- !, Res = '{}'(RA), bexpr2setlog(A,Env,Constr,RA). | |
200 | b2sext([A|T],Env,Constr,Res) :- bexpr2setlog(A,Env,CA,RA), | |
201 | Res = '{}'(RA/RT), % Setlog {RA/RT} | |
202 | b2sext(T,Env,CT,RT), | |
203 | sconjoin(CA,CT,Constr). | |
204 | ||
205 | do_not_generate_errors(Env) :- nonvar(Env), Env=[bind('$NO_ERRORS',V)|_], V==pred_true. | |
206 | ||
207 | add_translation_error(Env,Msg,TE) :- | |
208 | (do_not_generate_errors(Env) | |
209 | -> debug_mode(on), | |
210 | add_message(b2setlog,Msg,TE,TE) | |
211 | ; add_error(b2setlog,Msg,TE,TE) | |
212 | ). | |
213 | ||
214 | % Translating predicates to setlog | |
215 | % TO DO : quantifiers foreach/2, foreach/4, exists/2, exists/4 | |
216 | bpred2setlog(b(E,_T,_I),Env,SetLogConstr) :- b2p(E,Env,C),!, SetLogConstr=C. | |
217 | bpred2setlog(TE,Env,_) :- | |
218 | add_translation_error(Env,'Cannot convert B predicate to setlog:',TE), | |
219 | fail. | |
220 | ||
221 | b2p(BOP,Env,SetLogConstr) :- | |
222 | bin_pred(BOP,A,B,SetLogOperator),!, | |
223 | bexpr2setlog(A,Env,CA,RA), | |
224 | bexpr2setlog(B,Env,CB,RB), | |
225 | SLOG =.. [SetLogOperator,RA,RB], | |
226 | sconj([CA,CB,SLOG],SetLogConstr). | |
227 | b2p(truth,_,true). | |
228 | b2p(falsity,_,false). % TODO: check this | |
229 | % TODO: subset_strict for symbolic | |
230 | b2p(not_subset_strict(A,B),Env,Constr) :- | |
231 | bexpr2setlog(A,Env,CA,RA), | |
232 | bexpr2setlog(B,Env,CB,RB), | |
233 | create_not_subset(RA,B,Env,NotSubsetConstr), | |
234 | sdisjoin('='(RA,RB),NotSubsetConstr,Disj), | |
235 | sconj([CA,CB,Disj],Constr). | |
236 | b2p(subset(A,B),Env,Constr) :- | |
237 | bexpr2setlog(A,Env,CA,RA), | |
238 | create_subset(RA,B,Env,SubsetConstr), | |
239 | sconj([CA,SubsetConstr],Constr). | |
240 | b2p(not_subset(A,B),Env,Constr) :- | |
241 | bexpr2setlog(A,Env,CA,RA), | |
242 | create_not_subset(RA,B,Env,NotSubsetConstr), | |
243 | sconj([CA,NotSubsetConstr],Constr). | |
244 | b2p(member(A,B),Env,Constr) :- | |
245 | bexpr2setlog(A,Env,CA,RA), | |
246 | bmember2setlog(B,RA,Env,CB), sconjoin(CA,CB,Constr). | |
247 | b2p(not_member(A,B),Env,Constr) :- | |
248 | bexpr2setlog(A,Env,CA,RA), | |
249 | bnotmember2setlog(B,RA,Env,CB), sconjoin(CA,CB,Constr). | |
250 | %b2p(partition(A,List),Env,Constr) :- | |
251 | % bexpr2setlog(A,Env,CA,RA), ... | |
252 | b2p(equal(A,B),Env,Constr) :- | |
253 | bexpr2setlog(A,Env,CA,RA), | |
254 | bexpr2setlog(B,Env,CB,RB), | |
255 | (can_be_unified_in_translation(RA,A,RB,B) | |
256 | -> RA=RB, sconjoin(CA,CB,Constr) % perform unification here to avoid creating internal fresh Prolog vars | |
257 | ; sconj([CA,CB,'='(RA,RB)],Constr)). | |
258 | b2p(not_equal(A,B),Env,Constr) :- | |
259 | bexpr2setlog(A,Env,CA,RA), | |
260 | bexpr2setlog(B,Env,CB,RB), | |
261 | (can_be_unified_in_translation(RA,A,RB,B), | |
262 | can_be_negated(CA,NCA) | |
263 | -> RA=RB, sconjoin(CB,NCA,Constr) % perform unification here to avoid creating internal fresh Prolog vars | |
264 | ; can_be_unified_in_translation(RA,A,RB,B), | |
265 | can_be_negated(CB,NCB) | |
266 | -> RA=RB, sconjoin(CA,NCB,Constr) | |
267 | ; sconj([CA,CB,'neq'(RA,RB)],Constr)). | |
268 | b2p(negation(A),Env,CA) :- bnegpred2setlog(A,Env,CA). | |
269 | b2p(conjunct(A,B),Env,Constr) :- bpred2setlog(A,Env,CA), bpred2setlog(B,Env,CB), sconjoin(CA,CB,Constr). | |
270 | b2p(disjunct(A,B),Env,or(CA,CB)) :- bpred2setlog(A,Env,CA), bpred2setlog(B,Env,CB). | |
271 | b2p(implication(A,B),Env,implies(CA,CB)) :- bpred2setlog(A,Env,CA), bpred2setlog(B,Env,CB). | |
272 | b2p(equivalence(A,B),Env,Constr) :- | |
273 | bpred2setlog(A,Env,CA), bpred2setlog(B,Env,CB), | |
274 | sconjoin(implies(CA,CB),implies(CB,CA),Constr). | |
275 | b2p(exists(TypedIds,Body),Env,Constr) :- | |
276 | exclude(can_translate_typing_to_setlog,TypedIds,Rest), | |
277 | Rest=[],!, % TODO: extract typing from Body | |
278 | Constr = exists(Typing,CB), | |
279 | generate_typing_predicates(TypedIds,TypingPreds), | |
280 | conjunct_predicates(TypingPreds,TPS), | |
281 | bpred2setlog(TPS,Env,Typing), bpred2setlog(Body,Env,CB). | |
282 | b2p(forall(TypedIds,LHS,RHS),Env,Constr) :- | |
283 | include(can_translate_typing_to_setlog,TypedIds,Translatable), | |
284 | generate_typing_predicates(Translatable,TypingPreds), | |
285 | conjunct_predicates(TypingPreds,TPS), | |
286 | bpred2setlog(TPS,Env,Typing), | |
287 | bpred2setlog(LHS,Env,CLHS), % TODO: filter LHS into setlog typing and rest and provide warnings | |
288 | sconjoin(Typing,CLHS,SetLogLHS), | |
289 | Constr = foreach(SetLogLHS,SetLogRHS), | |
290 | bpred2setlog(RHS,Env,SetLogRHS). | |
291 | ||
292 | ||
293 | negate_pred(equal(A,B),not_equal(A,B)). | |
294 | negate_pred(not_equal(A,B),equal(A,B)). | |
295 | negate_pred(member(A,B),not_member(A,B)). | |
296 | negate_pred(not_member(A,B),member(A,B)). | |
297 | negate_pred(subset(A,B),not_subset(A,B)). | |
298 | negate_pred(not_subset(A,B),subset(A,B)). | |
299 | negate_pred(subset_strict(A,B),not_subset_strict(A,B)). | |
300 | negate_pred(not_subset_strict(A,B),subset_strict(A,B)). | |
301 | negate_pred(less(A,B),greater_equal(A,B)). | |
302 | negate_pred(greater_equal(A,B),less(A,B)). | |
303 | negate_pred(greater(A,B),less_equal(A,B)). | |
304 | negate_pred(less_equal(A,B),greater(A,B)). | |
305 | ||
306 | ||
307 | bnegpred2setlog(b(E,_T,_I),Env,SetLogConstr) :- b2p_neg(E,Env,C),!, SetLogConstr=C. | |
308 | bnegpred2setlog(TE,Env,_) :- add_translation_error(Env,'Cannot convert negated B predicate to setlog:',TE),fail. | |
309 | ||
310 | % translate negated predicate: | |
311 | b2p_neg(Pred,Env,CA) :- negate_pred(Pred,NPred),!, b2p(NPred,Env,CA). | |
312 | b2p_neg(negation(A),Env,CA) :- !, bpred2setlog(A,Env,CA). | |
313 | b2p_neg(disjunct(A,B),Env,Constr) :- !, bnegpred2setlog(A,Env,CA), bnegpred2setlog(B,Env,CB), sconjoin(CA,CB,Constr). | |
314 | b2p_neg(conjunct(A,B),Env,or(CA,CB)) :- !, bnegpred2setlog(A,Env,CA), bnegpred2setlog(B,Env,CB). | |
315 | b2p_neg(implication(A,B),Env,Constr) :- !, % not(a=>b) = not(not(a) or b) = a & not(b) | |
316 | bpred2setlog(A,Env,CA), bnegpred2setlog(B,Env,CB), sconjoin(CA,CB,Constr). | |
317 | b2p_neg(equivalence(A,B),Env,Constr) :- !, % not(a<=>b) = (a & not(b) or (not(a) & b)) | |
318 | NB = b(negation(B),pred,[]), | |
319 | ANB = b(conjunct(A,NB),pred,[]), | |
320 | NA = b(negation(A),pred,[]), | |
321 | NAB = b(conjunct(NA,B),pred,[]), | |
322 | b2p(disjunct(ANB,NAB),Env,Constr). | |
323 | b2p_neg(A,Env,neg(CA)) :- bpred2setlog(A,Env,CA). | |
324 | ||
325 | % check if we can unify two result variables in the translator, rather than at runtime | |
326 | can_be_unified_in_translation(RA,A,_,_) :- fresh_result_variable(RA,A). | |
327 | can_be_unified_in_translation(_,_,RB,B) :- fresh_result_variable(RB,B). | |
328 | fresh_result_variable(RA,BExpr) :- var(RA), \+ creates_bound_result_variable(BExpr). | |
329 | creates_bound_result_variable(b(identifier(_),_,_)). | |
330 | ||
331 | % declare which Setlog operators have a negative counterpart | |
332 | can_be_negated(un(A,B),nun(A,B)). | |
333 | can_be_negated(inters(A,B),ninters(A,B)). | |
334 | can_be_negated(diff(A,B),ndiff(A,B)). | |
335 | can_be_negated(inv(A,B),ninv(A,B)). | |
336 | can_be_negated(id(A,B),nid(A,B)). | |
337 | can_be_negated(dom(A,B),ndom(A,B)). | |
338 | can_be_negated(dompf(A,B),ndompf(A,B)). | |
339 | can_be_negated(ran(A,B),nran(A,B)). | |
340 | can_be_negated(comp(A,B,C),ncomp(A,B,C)). | |
341 | can_be_negated(dres(A,B,C),ndres(A,B,C)). | |
342 | can_be_negated(dares(A,B,C),ndares(A,B,C)). | |
343 | can_be_negated(drres(A,B,C),nrres(A,B,C)). | |
344 | can_be_negated(rares(A,B,C),nrares(A,B,C)). | |
345 | can_be_negated(oplus(A,B,C),noplus(A,B,C)). | |
346 | can_be_negated(rimg(A,B,C),nrimg(A,B,C)). | |
347 | can_be_negated(apply(A,B,C),napply(A,B,C)). | |
348 | ||
349 | % binary B predicates mapped to Setlog binary predicates: | |
350 | %bin_pred(member(A,B),A,B,in). % dealt with specially above | |
351 | %bin_pred(not_member(A,B),A,B,nin). % ditto | |
352 | %bin_pred(subset(A,B),A,B,subset). % explicit rules for symbolic values | |
353 | bin_pred(subset_strict(A,B),A,B,ssubset). | |
354 | %bin_pred(not_subset(A,B),A,B,nsubset). % explicit rules for symbolic values | |
355 | %bin_pred(not_subset_strict(A,B),A,B,nssubset). % does not exist in setlog! | |
356 | bin_pred(less(A,B),A,B,'<'). | |
357 | bin_pred(less_equal(A,B),A,B,'=<'). | |
358 | bin_pred(greater(A,B),A,B,'>'). | |
359 | bin_pred(greater_equal(A,B),A,B,'>='). | |
360 | %bin_pred(equal(A,B),A,B,'='). % dealt with specially above | |
361 | %bin_pred(not_equal(A,B),A,B,neq). % dealt with specially above to use negated Setlog operators if possible | |
362 | ||
363 | ||
364 | bmember2setlog(b(Set,_,_),Element,Env,Constr) :- | |
365 | b2mem(Set,Element,Env,Constr),!. | |
366 | bmember2setlog(Set,Element,Env,Constr) :- % default case: no special rule available | |
367 | bexpr2setlog(Set,Env,CA,RSet), | |
368 | sconjoin(CA,in(Element,RSet),Constr). | |
369 | ||
370 | b2mem(pow_subset(A),Element,Env,Constr) :- !, | |
371 | create_subset(Element,A,Env,Constr). | |
372 | b2mem(pow1_subset(A),Element,Env,Constr) :- !, | |
373 | create_subset(Element,A,Env,SubsetConstr), | |
374 | sconj([SubsetConstr,'neq'(Element,'{}')],Constr). | |
375 | b2mem(fin_subset(A),Element,Env,Constr) :- !, % Same, because Setlog only has finite sets anyway! | |
376 | b2mem(pow_subset(A),Element,Env,Constr). | |
377 | b2mem(fin1_subset(A),Element,Env,Constr) :- !, % Same, because Setlog only has finite sets anyway! | |
378 | b2mem(pow1_subset(A),Element,Env,Constr). | |
379 | b2mem(relations(A,B),Element,Env,Constr) :- !, | |
380 | create_domain(A,Element,Env,DomConstr), | |
381 | create_range(B,Element,Env,RanConstr), | |
382 | sconj([rel(Element),DomConstr,RanConstr],Constr). | |
383 | b2mem(partial_function(A,B),Element,Env,Constr) :- !, | |
384 | create_dom_pf(A,Element,Env,DomConstr), | |
385 | create_range(B,Element,Env,RanConstr), | |
386 | sconj([pfun(Element),DomConstr,RanConstr],Constr). | |
387 | b2mem(total_function(A,B),Element,Env,Constr) :- !, | |
388 | create_dom_tf(A,Element,Env,DomConstr), | |
389 | create_range(B,Element,Env,RanConstr), | |
390 | sconj([pfun(Element),DomConstr,RanConstr],Constr). | |
391 | b2mem(Set,Element,Env,Constr) :- | |
392 | is_symbolic_set(Set,Element,Env,ElConstr,_), !, % NATURAL(1) | |
393 | Constr = ElConstr. | |
394 | % there is no tfun use domain / range, for injective inverse and pfun | |
395 | % there is npfun and ndompf | |
396 | ||
397 | ||
398 | bnotmember2setlog(b(Set,_,_),Element,Env,Constr) :- | |
399 | b2not_mem(Set,Element,Env,Constr),!. | |
400 | bnotmember2setlog(Set,Element,Env,Constr) :- % default case: no special rule available | |
401 | bexpr2setlog(Set,Env,CA,RSet), | |
402 | sconjoin(CA,nin(Element,RSet),Constr). | |
403 | ||
404 | % special rules for not_member | |
405 | b2not_mem(relations(A,B),Element,Env,Constr) :- !, | |
406 | create_not_domain(A,Element,Env,NotDomConstr), | |
407 | is_just_type_and_infinite(B), % TODO: extend and disjoin | |
408 | sconj([rel(Element),NotDomConstr],Constr). | |
409 | b2not_mem(pow_subset(A),Element,Env,Constr) :- !, | |
410 | create_not_subset(Element,A,Env,Constr). | |
411 | b2not_mem(pow1_subset(A),Element,Env,Constr) :- !, | |
412 | create_not_subset(Element,A,Env,SubsetConstr), | |
413 | sdisjoin(SubsetConstr,'='(Element,'{}'),Constr). | |
414 | b2not_mem(fin_subset(A),Element,Env,Constr) :- !, % Same, because Setlog only has finite sets anyway! | |
415 | b2not_mem(pow_subset(A),Element,Env,Constr). | |
416 | b2not_mem(fin1_subset(A),Element,Env,Constr) :- !, % Same, because Setlog only has finite sets anyway! | |
417 | b2not_mem(pow1_subset(A),Element,Env,Constr). | |
418 | b2not_mem(partial_function(A,B),Element,Env,Constr) :- !, | |
419 | create_not_domain(A,Element,Env,DomConstr), | |
420 | create_not_range(B,Element,Env,NotRanConstr), | |
421 | sdisj([npfun(Element),DomConstr,NotRanConstr],Constr). | |
422 | % Note: we do not use create_not_dom_pf | |
423 | % somehow setlog does not seem to deal correctly with dompf inside a disjunction | |
424 | % example: :slog-double-check f:1..2 +-> 1..2 & not(f \/ {1 |-> 3} : 1..2 +->INTEGER) | |
425 | b2not_mem(Set,Element,Env,Constr) :- | |
426 | is_symbolic_set(Set,Element,Env,_,NegElConstr), !, % NATURAL(1) | |
427 | Constr = NegElConstr. | |
428 | ||
429 | create_dom_pf(A,_,_,Constr) :- is_just_type_and_infinite(A),!, | |
430 | % for finite types like BOOL we need to create the constraints below to let Setlog know the cardinality | |
431 | Constr=true. | |
432 | create_dom_pf(A,Func,Env,Constr) :- | |
433 | create_subset(Domain,A,Env,SubsetConstr), | |
434 | sconj([dompf(Func,Domain),SubsetConstr],Constr). | |
435 | % TODO: check if local variable Domain poses problem with setlog/Prolog negation; we may have to extract let-equalities separately from the constraints or maybe setlog could add a let_predicate construct | |
436 | ||
437 | create_domain(A,_,_,Constr) :- is_just_type_and_infinite(A),!, Constr=true. | |
438 | create_domain(A,Func,Env,Constr) :- | |
439 | create_subset(Domain,A,Env,SubsetConstr), | |
440 | sconj([dom(Func,Domain),SubsetConstr],Constr). | |
441 | ||
442 | % check if domain of a partial function is not a subset of a provided set A | |
443 | create_not_dom_pf(A,_,_,Constr) :- is_just_type_and_infinite(A),!, | |
444 | % for finite types like BOOL we need to create the constraints below to let Setlog know the cardinality | |
445 | Constr=false. | |
446 | create_not_dom_pf(A,Func,Env,Constr) :- | |
447 | create_not_subset(Domain,A,Env,NotSubsetConstr), | |
448 | sconj([dompf(Func,Domain),NotSubsetConstr],Constr). | |
449 | ||
450 | create_not_domain(A,_,_,Constr) :- is_just_type_and_infinite(A),!, Constr=false. | |
451 | create_not_domain(A,Func,Env,Constr) :- | |
452 | create_not_subset(Domain,A,Env,SubsetConstr), | |
453 | sconj([dom(Func,Domain),SubsetConstr],Constr). | |
454 | ||
455 | create_dom_tf(A,Func,Env,Constr) :- | |
456 | bexpr2setlog(A,Env,CA,DomType), | |
457 | sconj([CA,dompf(Func,DomType)],Constr). | |
458 | ||
459 | % create range constraint for a function | |
460 | create_range(A,_,_,Constr) :- is_just_type_and_infinite(A),!, Constr=true. | |
461 | create_range(A,Func,Env,Constr) :- | |
462 | create_subset(Range,A,Env,SubsetConstr), | |
463 | sconj([ran(Func,Range),SubsetConstr],Constr). | |
464 | ||
465 | % create setlog constraint for Set1 <: Set2, where Set1 already transformed | |
466 | create_subset(SetlogSet1,b(Set2,_,_),Env,Constr) :- | |
467 | b2mem(Set2,VAR,Env,VAR_Constr),!, % we can create a membership constraint | |
468 | Constr = foreach(in(VAR,SetlogSet1),VAR_Constr). | |
469 | create_subset(SetlogSet1,BSet2,Env,Constr) :- | |
470 | bexpr2setlog(BSet2,Env,CA,SetlogSet2), | |
471 | sconj([CA,subset(SetlogSet1,SetlogSet2)],Constr). | |
472 | ||
473 | % create range constraint for a function | |
474 | create_not_range(A,_,_,Constr) :- is_just_type_and_infinite(A),!, Constr=false. | |
475 | create_not_range(A,Func,Env,Constr) :- | |
476 | create_not_subset(Range,A,Env,SubsetConstr), | |
477 | sconj([ran(Func,Range),SubsetConstr],Constr). | |
478 | ||
479 | % create setlog constraint for not (Set1 <: Set2), where Set1 already transformed | |
480 | create_not_subset(SetlogSet1,b(Set2,_,_),Env,Constr) :- | |
481 | b2not_mem(Set2,VAR,Env,VAR_NegConstr),!, % we can create a not-membership constraint | |
482 | Constr = exists(in(VAR,SetlogSet1),VAR_NegConstr). | |
483 | create_not_subset(SetlogSet1,BSet2,Env,Constr) :- | |
484 | bexpr2setlog(BSet2,Env,CA,SetlogSet2), | |
485 | sconj([CA,nsubset(SetlogSet1,SetlogSet2)],Constr). | |
486 | ||
487 | % translate symbolic set in set of VAR satisfying constraint | |
488 | is_symbolic_set(integer_set('NATURAL'),VAR,_,'>='(VAR,0),'<'(VAR,0)). | |
489 | is_symbolic_set(integer_set('NATURAL1'),VAR,_,'>'(VAR,0),'=<'(VAR,0)). | |
490 | %TODO: support comprehension sets; we could move code to b2mem and b2not_mem | |
491 | ||
492 | :- use_module(probsrc(typing_tools),[is_infinite_type/1, is_provably_finite_type/1]). | |
493 | :- use_module(probsrc(bsyntaxtree),[is_just_type/1, get_texpr_type/2]). | |
494 | is_just_type_and_infinite(A) :- is_just_type(A), | |
495 | get_texpr_type(A,Type), | |
496 | is_infinite_type(Type). | |
497 | ||
498 | ||
499 | % utilities to conjoin Setlog predicates: | |
500 | sconjoin(false,_,R) :- !, R=false. | |
501 | sconjoin(true,A,R) :- !, R=A. | |
502 | sconjoin(_,false,R) :- !,R=false. | |
503 | sconjoin(A,true,R) :- !,R=A. | |
504 | sconjoin(A,B,'&'(A,B)). | |
505 | ||
506 | sconj([],true). | |
507 | sconj([H],R) :- !, R=H. | |
508 | sconj([H|T],R) :- sconj(T,TC),sconjoin(H,TC,R). | |
509 | ||
510 | ||
511 | sdisjoin(true,_,R) :- !, R=true. | |
512 | sdisjoin(false,A,R) :- !, R=A. | |
513 | sdisjoin(A,false,R) :- !,R=A. | |
514 | sdisjoin(_,true,R) :- !,R=true. | |
515 | sdisjoin(A,B,'or'(A,B)). | |
516 | ||
517 | sdisj([],false). | |
518 | sdisj([H],R) :- !, R=H. | |
519 | sdisj([H|T],R) :- sdisj(T,TC),sdisjoin(H,TC,R). | |
520 | ||
521 | :- dynamic path_to_setlog/1, path_to_setlog_wrapper_binary/1. | |
522 | :- if(current_prolog_flag(dialect, swi)). | |
523 | path_to_setlog('../prob_related/setlog_wrapper/setlog498-13h1.pl'). | |
524 | :- endif. | |
525 | ||
526 | :- use_module(probsrc(pathes_lib),[check_lib_contents/3]). | |
527 | :- use_module(library(file_systems),[file_exists/1]). | |
528 | get_path_to_setlog_cli_wrapper_qlf(Path) :- | |
529 | absolute_file_name(prob_lib('setlog-cli.qlf'), Path), | |
530 | (file_exists(Path) -> true | |
531 | ; add_warning(b2setlog,'No setlog wrapper available at: ',Path), | |
532 | check_lib_contents(user_error,setlog,verbose), | |
533 | fail | |
534 | ). | |
535 | % project for wrapper is https://gitlab.cs.uni-duesseldorf.de/stups/prob/setlog_wrapper | |
536 | ||
537 | % --------------------------------------------------- | |
538 | ||
539 | :- use_module(probsrc(translate), [generate_typing_predicates/2]). | |
540 | :- use_module(probsrc(bsyntaxtree), [find_typed_identifier_uses/2, conjunct_predicates/2]). | |
541 | add_typing_pred(BPred,BPred2) :- | |
542 | find_typed_identifier_uses(BPred,TypedIds), % we will have to do this also for quantifiers/set compr. later | |
543 | include(can_translate_typing_to_setlog,TypedIds,TranslatableIds), | |
544 | generate_typing_predicates(TranslatableIds,TypingPreds), | |
545 | %translate:nested_print_bexpr(TypingPreds),nl, | |
546 | conjunct_predicates([BPred|TypingPreds],BPred2). | |
547 | ||
548 | can_translate_typing_to_setlog(b(identifier(ID),Type,Pos)) :- | |
549 | (simple_finite_type(Type) -> true | |
550 | ; only_infinite_type(Type) -> fail | |
551 | % TODO: we can check things like set(couple(integer,boolean)) by using range(f) <: BOOL | |
552 | ; add_message(b2setlog,'Not translating to Setlog typing for ',ID,Pos),fail | |
553 | ). | |
554 | ||
555 | simple_finite_type(boolean). | |
556 | simple_finite_type(global(G)) :- is_provably_finite_type(global(G)). | |
557 | simple_finite_type(set(boolean)). | |
558 | simple_finite_type(set(global(G))) :- is_provably_finite_type(global(G)). | |
559 | ||
560 | only_infinite_type(integer). | |
561 | only_infinite_type(real). | |
562 | only_infinite_type(string). | |
563 | only_infinite_type(set(T)) :- only_infinite_type(T). | |
564 | only_infinite_type(couple(A,B)) :- only_infinite_type(A), only_infinite_type(B). | |
565 | ||
566 | solve_pred_with_setlog(BPred,LocalState,Res) :- | |
567 | get_preference(time_out, Timeout), | |
568 | solve_pred_with_setlog(BPred,LocalState,[timeout(Timeout)],Res). | |
569 | solve_pred_with_setlog(BPred,LocalState,Options,Res) :- | |
570 | add_typing_pred(BPred,BPred2), | |
571 | write('Translating: '),translate:print_bexpr(BPred2),nl, | |
572 | bpred2setlog(BPred2,LocalState,SetlogConstraint),!, | |
573 | length(LocalState,Len), % fix length | |
574 | !, | |
575 | ( numbervars(LocalState,0,_), | |
576 | format('Setlog translation (~w ids):~n ~w~n',[Len,SetlogConstraint]), | |
577 | fail ; true), | |
578 | (path_to_setlog(Path), | |
579 | use_module(Path,[setlog/1]) | |
580 | -> setlog_solve_direct(SetlogConstraint,LocalState,Options,Res) | |
581 | ; get_path_to_setlog_cli_wrapper_qlf(QlfPath) | |
582 | -> setlog_solve_with_wrapper(QlfPath,SetlogConstraint,LocalState,Options,Res) | |
583 | ; Res=no_solution_found(setlog_not_available) | |
584 | ). | |
585 | solve_pred_with_setlog(_,[],_,Res) :- Res=no_solution_found(translation_failed). | |
586 | ||
587 | % solve setlog constraint directly with loaded setlog module (works when running ProB from SWI) | |
588 | setlog_solve_direct(SetlogConstraint,LocalState,Options,Res) :- | |
589 | member(timeout(TimeOutMs),Options),!, | |
590 | safe_time_out(setlog_solve_direct(SetlogConstraint,LocalState,Res),TimeOutMs,TimeOutRes), | |
591 | (TimeOutRes=time_out -> | |
592 | format('Timeout in Setlog Prover (~w ms)~n',[TimeOutMs]), | |
593 | Res=no_solution_found(time_out) | |
594 | ; true). | |
595 | setlog_solve_direct(SetlogConstraint,LocalState,_Options,Res) :- | |
596 | setlog_solve_direct(SetlogConstraint,LocalState,Res). | |
597 | ||
598 | setlog_solve_direct(SetlogConstraint,LocalState,Res) :- | |
599 | catch( | |
600 | (setlog(SetlogConstraint) | |
601 | -> format('Setlog solution:~n ~w~n',[LocalState]), % todo: translate to B, possibly ground empty sets | |
602 | maplist(setlog_bind2b,LocalState,Sol), | |
603 | Res=solution(Sol) | |
604 | ; Res=contradiction_found | |
605 | ), | |
606 | setlog_excpt(Exc), | |
607 | Res=no_solution_found(setlog_excpt(Exc)) | |
608 | ). | |
609 | ||
610 | :- use_module(library(codesio),[format_to_codes/3,write_to_codes/2,read_term_from_codes/3]). | |
611 | :- use_module(probsrc(system_call), [system_call/5]). | |
612 | % solve setlog constraint via external setlog wrapper binary or via swipl | |
613 | setlog_solve_with_wrapper(QlfPath,SetlogConstraint,LocalState,Options,Res) :- | |
614 | term_variables(SetlogConstraint,Vars), | |
615 | maplist(get_variable_name,Vars,VarNames), | |
616 | %format('VarNames: ~q ~n',[VarNames]), | |
617 | %numbervars(SetlogConstraint,0,_), | |
618 | format_to_codes('~q',[SetlogConstraint],SlogCS), | |
619 | atom_codes(SlogConstraintAtom,SlogCS), | |
620 | (member(timeout(TO),Options) -> get_atom(TO,TOAtom) ; TOAtom='2500'), | |
621 | format_to_codes('consult(~q), main, halt ; halt(1).',[QlfPath],GoalCodes), | |
622 | atom_codes(SwiGoal,GoalCodes), | |
623 | debug_format(19,'Calling setlog wrapper (goal ~w) with ~w --groundsol --timeout ~w (vars ~w)~n', | |
624 | [SwiGoal,SlogConstraintAtom,TOAtom,Vars]), | |
625 | % TODO Allow changing swipl command/path | |
626 | %debug_format(19,'Using SWI Prolog binary at: ~w~n',[SwiPath]), | |
627 | (debug_mode(on) -> TArgs = ['--verbose'] ; TArgs=[]), | |
628 | system_call(path(swipl),['-g',SwiGoal, | |
629 | '--',SlogConstraintAtom, | |
630 | '--groundsol','--timeout',TOAtom|TArgs],Text,ErrorTextAsCodeList,Exit), | |
631 | debug_format(9,'Exit Status: ~w~n-----~nStdout: ~s~n-----~nStderr: ~s~n',[Exit,Text,ErrorTextAsCodeList]), | |
632 | (ErrorTextAsCodeList=[], | |
633 | Exit=exit(0) | |
634 | -> process_setlog_result(Text,VarNames,Res), | |
635 | (var(Res) | |
636 | -> maplist(setlog_bind2b,LocalState,Sol),Res=solution(Sol) | |
637 | ; true) | |
638 | ; add_error(b2setlog,'Errors occured when running setlog wrapper, exit status:',Exit), | |
639 | format(user_error,'Error Messages:~n~s~n',[ErrorTextAsCodeList]), | |
640 | format(user_error,'Output Messages:~n~s~n',[Text]), | |
641 | Res=error | |
642 | ). | |
643 | ||
644 | % convert number to atom if necessary, system call does not like numbers as args | |
645 | get_atom(A,R) :- atom(A),!,R=A. | |
646 | get_atom(Nr,Atom) :- number(Nr), number_codes(Nr,C),atom_codes(Atom,C). | |
647 | ||
648 | % get the name of a Prolog variable | |
649 | get_variable_name(Var,Name=Var) :- | |
650 | write_to_codes(Var,Codes), | |
651 | atom_codes(Name,Codes). | |
652 | %get_variable_name(Var,Name=Var) :- | |
653 | % format_to_codes('var(~q).',[Var],Codes), | |
654 | % read_term_from_codes(Codes,_,[variable_names(Names)]), | |
655 | % Names = [Name=Var]. | |
656 | ||
657 | process_setlog_result([],_,_) :- !. | |
658 | process_setlog_result(Codes,VarNames,Res) :- | |
659 | append("setlog_",_,Codes), % we have a setlog result fact | |
660 | skip_until_eol(Codes,Line1,Rest),!, | |
661 | %format('Processing : ~s~n',[Line1]), | |
662 | read_term_from_codes(Line1,Term,[variable_names(_VN2)]), | |
663 | debug_format(19,'Read term: ~w~n',[Term]), | |
664 | procces_setlog_result_term(Term,VarNames,Res), | |
665 | process_setlog_result(Rest,VarNames,Res). | |
666 | process_setlog_result(Codes,VarNames,Res) :- | |
667 | skip_until_eol(Codes,_Skipping,Rest),!, | |
668 | process_setlog_result(Rest,VarNames,Res). | |
669 | ||
670 | procces_setlog_result_term(setlog_variable_bindings(Bindings),VarNames,_) :- !, | |
671 | maplist(process_setlog_binding(VarNames),Bindings). | |
672 | procces_setlog_result_term(setlog_version(Version),_,_) :- !, | |
673 | format('Setlog version: ~w~n',[Version]). | |
674 | procces_setlog_result_term(setlog_result(Result),_,Res) :- !, | |
675 | format('Setlog result: ~w~n',[Result]), % should be success for solved constraint | |
676 | (convert_setlog_result(Result,Res) -> true | |
677 | ; add_error(b2setlog,'Illegal setlog result:',Result), | |
678 | Res = error). | |
679 | procces_setlog_result_term(_,_,_). | |
680 | ||
681 | convert_setlog_result(success,_). % keep variable, will be bound to solution(_) later | |
682 | convert_setlog_result(failure,contradiction_found). | |
683 | convert_setlog_result(time_out,no_solution_found(time_out)). | |
684 | convert_setlog_result(timeout,no_solution_found(time_out)). | |
685 | ||
686 | process_setlog_binding(_,true) :- !. | |
687 | process_setlog_binding(VarNames,'='(VariableName,Term)) :- | |
688 | debug_format(9,'~q~n',[equality(VariableName,Term,VarNames)]), | |
689 | member(VariableName=Var,VarNames),!, | |
690 | if(Var=Term,true, | |
691 | format('Cannot apply setlog binding to B: ~w=~w~n',[VariableName,Term])). | |
692 | process_setlog_binding(_,Binding) :- | |
693 | add_error(b2setlog,'Illegal setlog result binding:',Binding). | |
694 | ||
695 | % skip until end of line or file | |
696 | skip_until_eol([],[],[]). | |
697 | skip_until_eol([10|Rest],[],Rest). | |
698 | skip_until_eol([13|Rest],[],Rest). | |
699 | skip_until_eol([H|T],[H|LT],Rest) :- skip_until_eol(T,LT,Rest). | |
700 | ||
701 | % ------------------------- | |
702 | ||
703 | setlog_bind2b(bind(ID,Val),bind(ID,TVal)) :- (setlog_value2b(Val,TVal) -> true ; TVal = term(Val)). | |
704 | ||
705 | :- use_module(probsrc(custom_explicit_sets),[construct_interval_closure/3]). | |
706 | %setlog_value2b(F,_) :- nonvar(F),functor(F,FF,NN), print(setlog_value2b(FF/NN,F)),nl,fail. | |
707 | setlog_value2b(V,Res) :- var(V),!,Res=V. | |
708 | setlog_value2b(Nr,Res) :- integer(Nr),!,Res=int(Nr). | |
709 | setlog_value2b(pred_false,Res) :- !, Res=pred_false. | |
710 | setlog_value2b(pred_true,Res) :- !, Res=pred_true. | |
711 | setlog_value2b([A,B],(TA,TB)) :- !, | |
712 | setlog_value2b(A,TA), setlog_value2b(B,TB). | |
713 | setlog_value2b('{}',R) :- !, R=[]. | |
714 | setlog_value2b('{}'(A/T),R) :- !, R=[TA|TT], setlog_value2b(A,TA),setlog_value2b(T,TT). | |
715 | setlog_value2b('{}'(A),TA) :- !, setlog_set_value2b(A,TA). | |
716 | setlog_value2b(string(S),R) :- !, R=string(S). | |
717 | setlog_value2b(fd(Nr,S),R) :- !, R=fd(Nr,S). | |
718 | setlog_value2b(int(From,To),R) :- | |
719 | setlog_value2b(From,int(F)), | |
720 | setlog_value2b(To,int(T)),!, construct_interval_closure(F,T,R). | |
721 | setlog_value2b(Val,_R) :- Val=..[Func|Args],length(Args,Len), | |
722 | print(unsupported_val(Val,func(Func/Len),args(Args))),nl, | |
723 | true. %R=term(Val). | |
724 | % TODO: sometimes we get quoted variable names from setlog via setlog-wrapper | |
725 | ||
726 | setlog_set_value2b(Var,R) :- var(Var),!,R=Var. | |
727 | %setlog_set_value2b(F,_) :- functor(F,FF,NN), print(setv(FF/NN,F)),nl,fail. | |
728 | setlog_set_value2b(','(A,T),R) :- !, R=[TA|TB], setlog_value2b(A,TA), | |
729 | setlog_set_value2b(T,TB). | |
730 | setlog_set_value2b('/'(A,T),R) :- !, R=[TA|TT], setlog_value2b(A,TA),setlog_value2b(T,TT). | |
731 | setlog_set_value2b(A,R) :- setlog_value2b(A,TA),!,R=[TA]. | |
732 | setlog_set_value2b(Val,term(Val)) :- print(unsupported_set_val(Val)),nl. | |
733 | ||
734 | % ---------------- | |
735 | ||
736 | ||
737 | :- use_module(probsrc(tools), [start_ms_timer/1,stop_ms_timer_with_msg/2]). | |
738 | :- use_module(probsrc(tools_meta),[safe_time_out/3]). | |
739 | prove_using_setlog(Goal,Hypotheses,Opts,TimeOutMs,Res) :- | |
740 | % quite often 0 or 1 ms are enough for TimeOutMs | |
741 | (member(disprover_option(po_label(Label)),Opts) -> true ; Label='?'), | |
742 | format('Starting Setlog Prover (timeout ~w ms) for \'~w\' ~n',[TimeOutMs,Label]), | |
743 | start_ms_timer(Timer), | |
744 | prove_sequent_with_setlog(Goal,Hypotheses,[timeout(TimeOutMs)],Res), | |
745 | stop_ms_timer_with_msg(Timer,'Setlog Prover completed'). | |
746 | ||
747 | prove_sequent_with_setlog(TGoal,THypotheses,Options,Res) :- | |
748 | % build predicate H1 & H2 .... & not Goal | |
749 | create_negation(TGoal,NegatedGoal), | |
750 | (can_translate_to_setlog(NegatedGoal) | |
751 | -> include(can_translate_to_setlog,THypotheses,OkHyps), | |
752 | conjunct_predicates([NegatedGoal|OkHyps],Predicate), | |
753 | (debug_mode(on) -> write('SETLOG:'),nl,translate:nested_print_bexpr(Predicate),nl ; true), | |
754 | solve_pred_with_setlog(Predicate,_,Options,Res) | |
755 | ; Res = no_solution_found(cannot_translate_goal) | |
756 | ), | |
757 | format('Setlog prover result: ~w~n',[Res]). | |
758 | ||
759 | can_translate_to_setlog(b(E,_T,_I)) :- | |
760 | b2p(E,[bind('$NO_ERRORS',pred_true)|_Env],_C),!. | |
761 | can_translate_to_setlog(E) :- | |
762 | debug_mode(on), | |
763 | add_message(b2setlog,'Ignoring hypothesis: ',E,E),fail. | |
764 | ||
765 | /* | |
766 | | ?- b2e(union(b(identifier(a),any,[]),b(identifier(A),any,[])),Env,Constraints,ResultVar). | |
767 | A = a, | |
768 | Env = [a/_A|_B], | |
769 | Constraints = un(_A,_A,ResultVar) ? | |
770 | ||
771 | | ?- | ?- b2p(member(b(integer(1),integer,[]),b(union(b(identifier(A),any,[]),b(identifier(A),any,[])),any,[])),Env,Constraints). | |
772 | A = a, | |
773 | Env = [a/_A|_B], | |
774 | Constraints = &(un(_A,_A,_C),in(1,_C)) ? | |
775 | ||
776 | >>> :slog f:INTEGER +-> INTEGER & f(x)=y & g=f<+{x|->y+1} & g(x)=y | |
777 | ||
778 | % :slog n>0 & f:1..n +-> 1..n & x:1..n & not(f<+{1|->x}:1..n +->1..n) | |
779 | ||
780 | x<:{5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100} & card(x)=15 & (55/:x => 65:x) & (45/:x => 75:x) & (35 /:x => 85:x) | |
781 | */ |