1 | | % (c) 2015-2024 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, |
2 | | % Heinrich Heine Universitaet Duesseldorf |
3 | | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) |
4 | | |
5 | | :- module(model_translation, [translate_smt_model_to_b_values/4, |
6 | | store_explicit_set_unique_id/2, |
7 | | consistent_deferred_set_sizes/0, |
8 | | assert_virtual_deferred_set_id/2, |
9 | | clear_translation_state/0]). |
10 | | |
11 | | :- use_module(library(lists), [maplist/3,maplist/4, |
12 | | append/2,select/3,max_member/2]). |
13 | | :- use_module(library(avl)). |
14 | | :- use_module(library(codesio), [read_from_codes/2]). |
15 | | |
16 | | :- use_module(probsrc(preferences), [get_preference/2]). |
17 | | :- use_module(probsrc(b_ast_cleanup), [clean_up/3]). |
18 | | :- use_module(probsrc(translate), [translate_bvalue/2]). |
19 | | :- use_module(probsrc(tools), [arg_is_number/2,split_atom/3,atom_to_number/2,ajoin/2]). |
20 | | :- use_module(probsrc(tools_strings), [convert_to_number/2, atom_prefix/2]). |
21 | | :- use_module(probsrc(error_manager),[]). |
22 | | :- use_module(probsrc(tools),[]). |
23 | | :- use_module(probsrc(error_manager), [add_error/3,add_error/4, |
24 | | add_internal_error/2,add_error_fail/3,check_error_occured/2]). |
25 | | :- use_module(probsrc(bsyntaxtree), [safe_create_texpr/3, |
26 | | create_texpr/4, |
27 | | unique_typed_id/3, |
28 | | create_equality/3, |
29 | | conjunction_to_list/2, |
30 | | conjunct_predicates/2, |
31 | | disjunct_predicates/2, |
32 | | get_texpr_type/2, |
33 | | find_identifier_uses/3, |
34 | | create_negation/2]). |
35 | | :- use_module(probsrc(custom_explicit_sets), [try_expand_custom_set_to_list/4]). |
36 | | :- use_module(probsrc(b_global_sets), [b_global_deferred_set/1, b_global_set/1, b_type2_set/2, global_type/2, get_user_defined_scope/4, unfixed_deferred_set/1]). |
37 | | :- use_module(probsrc(b_interpreter),[b_test_boolean_expression_cs/5, b_compute_expression_nowf/6]). |
38 | | |
39 | | %:- use_module(probsrc(self_check), [assert_must_succeed/1]). |
40 | | |
41 | | :- use_module(solver_dispatcher). |
42 | | |
43 | | :- use_module(probsrc(module_information),[module_info/2]). |
44 | | :- module_info(group,smt_solvers). |
45 | | :- module_info(description,'This module translates the models found by an SMT-solvers to a ProB state.'). |
46 | | |
47 | | :- set_prolog_flag(double_quotes, codes). |
48 | | |
49 | | :- dynamic explicit_set_cache/2, fd_var_of_z3/2, virtual_deferred_set_id/2, linecount/1. |
50 | | |
51 | | clear_translation_state :- |
52 | | retractall(virtual_deferred_set_id(_,_)), |
53 | | retractall(fd_var_of_z3(_,_)), |
54 | | retractall(explicit_set_cache(_, _)). |
55 | | |
56 | | assert_virtual_deferred_set_id(EnumElm, FdVar) :- |
57 | | asserta(virtual_deferred_set_id(EnumElm, FdVar)). |
58 | | |
59 | | % Store explicit sets for universally quantified translations to prevent vanishing type information |
60 | | % when translating universal quantifiers from SMT-Lib to B (e.g., for general_intersection). |
61 | | store_explicit_set_unique_id(SetAst, UniqueIdName) :- |
62 | | get_texpr_type(SetAst, Type), |
63 | | unique_typed_id("inner_set", Type, UniqueId), |
64 | | UniqueId = b(identifier(UniqueIdName),_,_), |
65 | | asserta(explicit_set_cache(UniqueIdName, SetAst)). |
66 | | |
67 | | %% consistent_deferred_set_sizes. |
68 | | % We collect all global FD variables during the translation of a model found by Z3 to |
69 | | % check if the considered deferred set size (maximum of all global FD variables) is smaller |
70 | | % than the value considered by ProB (preference DEFAULT_SETSIZE). |
71 | | % If such models are refuted, Z3 behaves as ProB. |
72 | | % Otherwise, we might translate a solution using less global FD variables than defined by ProB. |
73 | | consistent_deferred_set_sizes :- |
74 | | findall(DS, (b_global_deferred_set(DS), unfixed_deferred_set(DS)), DeferredSets), |
75 | | consistent_deferred_set_sizes(DeferredSets). |
76 | | |
77 | | %% consistent_deferred_set_sizes(DeferredSets). |
78 | | consistent_deferred_set_sizes([]). |
79 | | consistent_deferred_set_sizes([DeferredSet|T]) :- |
80 | | findall(FdVarOfZ3, retract(fd_var_of_z3(DeferredSet,FdVarOfZ3)), FdVarsOfZ3), |
81 | | FdVarsOfZ3 \== [], |
82 | | !, |
83 | | max_member(MaxFdVarOfZ3, FdVarsOfZ3), |
84 | | ( get_user_defined_scope(DeferredSet,Low,Up,_Span) |
85 | | -> DeferredSetSize is 1+Up-Low |
86 | | ; get_preference(globalsets_fdrange, DeferredSetSize) |
87 | | ), |
88 | | % the case for MaxFdVarOfZ3 > DeferredSetSize is already handled in handle_globalsets_fdrange_contradiction |
89 | | MaxFdVarOfZ3 == DeferredSetSize, |
90 | | consistent_deferred_set_sizes(T). |
91 | | consistent_deferred_set_sizes([_|T]) :- |
92 | | % this deferred set is not part of the solution and can be ignored |
93 | | consistent_deferred_set_sizes(T). |
94 | | |
95 | | translate_smt_model_to_b_values(Solver,State,Identifiers,Bindings) :- |
96 | ? | get_full_model_as_avl(Solver,AVL), % parse it only once for all identifiers |
97 | ? | maplist(translate_smt_model_to_b_value(Solver,State,AVL),Identifiers,Bindings). |
98 | | |
99 | | translate_smt_model_to_b_value(Solver,State,FullModelAVL, |
100 | | b(identifier(Id),Type,_Infos),binding(Id,Value,PPValue)) :- |
101 | ? | member(id(Id,Expr),State), |
102 | | smt_solver_interface_call(Solver,get_model_string(Expr,String)), !, |
103 | | atom_codes(String,Codes), |
104 | | %format('Result of get_model_string:~n~s~n---~n',[Codes]), |
105 | | parse_lisp_style_expressions([E],Codes,[]), !, |
106 | | (Solver == cvc4 -> translate_cvc4_tree(E,Type,Value) ; |
107 | ? | Solver == z3 -> translate_z3_tree_for_id(Id,E,FullModelAVL,Type,Value) ; |
108 | | fail), |
109 | | |
110 | | (translate_bvalue(Value,PPValue) -> true ; PPValue='**pretty-print failed**'). |
111 | | |
112 | | translate_z3_tree_for_id(Id,EscapedId,_,Type,Result) :- |
113 | | % the id might have been escaped in z3 (e.g. due to ticks) |
114 | | ajoin(['|',Id,'|'],EscapedId), !, |
115 | | % variable is not assigned (hence z3 returns its name) |
116 | | % just ground it somehow |
117 | | z3_ground_result(Type,Result). |
118 | | translate_z3_tree_for_id(_,E,FullModelAVL,Type,Result) :- |
119 | ? | translate_z3_tree_and_check(E,FullModelAVL,Type,Result,translate_z3_tree4). |
120 | | |
121 | | |
122 | | translate_z3_record(Env, field(Name,BType), CVCVal, field(Name,BVal)) :- |
123 | | translate_z3_expr(CVCVal, Env, BType, BVal). |
124 | | |
125 | | % ----------------------------- |
126 | | |
127 | | % performs additional sanity check of computed values: |
128 | | translate_z3_tree_and_check(SingleVal,FullModelAVL,ReturnType,Value,PP) :- |
129 | ? | translate_z3_tree_aux(SingleVal,FullModelAVL,ReturnType,Value), |
130 | | check_value(ReturnType,Value,SingleVal,PP). |
131 | | |
132 | | translate_z3_tree_aux(Tree,FullModelAVL,boolean,Res) :- |
133 | | % Z3 might return a quantifier for Boolean values since version 4.12.0 |
134 | | !, |
135 | | translate_z3_predicate(Tree,env([],FullModelAVL),BPred), |
136 | | ( b_test_boolean_expression_cs(BPred, [], [],'translating Z3 Boolean value',0) |
137 | | -> Res = pred_true |
138 | | ; Res = pred_false |
139 | | ). |
140 | | translate_z3_tree_aux(Tree,FullModelAVL,Type,Res) :- |
141 | ? | translate_z3_expr(Tree,env([],FullModelAVL),Type,BExpr), |
142 | | b_compute_expression_nowf(BExpr,[],[],Res,'translating Z3 value',0). |
143 | | |
144 | | check_value(_,identifier(A),_,_) :- atom(A),!. |
145 | | check_value(integer,I,SV,PP) :- \+ (I=int(Nr), number(Nr)),!, |
146 | | add_internal_error('Illegal Z3 value, not number computed:', PP:SV:I), fail. |
147 | | check_value(boolean,B,SV,PP) :- B \= pred_true , B\= pred_false, !, |
148 | | add_internal_error('Illegal Z3 value, not boolean computed:', PP:SV:B), fail. |
149 | | check_value(_,_,_,_). |
150 | | |
151 | | %% get_typing_predicates(+BVars, -TypingPredList). |
152 | | % Create typing predicates for variables either from explicit_set_cache/2 |
153 | | % or more generally using generate_typing_predicates/2. |
154 | | get_typing_predicates(BVars, TypingPredList) :- |
155 | | get_typing_predicates(BVars, [], [], TypingPredList). |
156 | | |
157 | | get_typing_predicates([], NotCached, Acc, TypingPredList) :- |
158 | | translate:generate_typing_predicates(NotCached, TTypingPredList), |
159 | | append(Acc, TTypingPredList, TypingPredList). |
160 | | get_typing_predicates([BVar|T], NotCached, Acc, TypingPredList) :- |
161 | | BVar = b(identifier(IdName),_,_), |
162 | | explicit_set_cache(IdName, ExplicitSet), |
163 | | !, |
164 | | TypingPred = b(member(BVar,ExplicitSet),pred,[]), |
165 | | get_typing_predicates(T, NotCached, [TypingPred|Acc], TypingPredList). |
166 | | get_typing_predicates([BVar|T], NotCached, Acc, TypingPredList) :- |
167 | | get_typing_predicates(T, [BVar|NotCached], Acc, TypingPredList). |
168 | | |
169 | | is_global_type_variable_name(env(Ids,_), VarName, GlobalType) :- |
170 | ? | member(b(identifier(VarName),GlobalType,_), Ids), |
171 | | GlobalType = global(_). |
172 | | is_global_type_variable_name(_, VarName, global(Set)) :- |
173 | | split_atom(VarName, ['!'], [Set,_,_]), |
174 | | b_global_set(Set). |
175 | | |
176 | | % enumerated and deferred sets are translated as integers |
177 | | % we have to check for global types to identify integers as such, see e.g. (= 0 c) where c is a global type variable |
178 | | typecheck_for_global_type(Left, _, Env, Type) :- |
179 | | atom(Left), |
180 | | is_global_type_variable_name(Env, Left, GlobalType), |
181 | | !, |
182 | | Type = GlobalType. |
183 | | typecheck_for_global_type(_, Right, Env, Type) :- |
184 | | atom(Right), |
185 | | is_global_type_variable_name(Env, Right, GlobalType), |
186 | | !, |
187 | | Type = GlobalType. |
188 | | typecheck_for_global_type(_, _, _, _). % no global type; use a variable which is set afterwards |
189 | | |
190 | | % ------------------------------- |
191 | | |
192 | | % TODO: do we really need this function anymore: |
193 | | translate_z3_expr_using_full_model(Expr,Type,Result) :- |
194 | | get_full_model_as_avl(z3,AVL), |
195 | | translate_z3_expr(Expr,env([],AVL),Type,Result). |
196 | | |
197 | | get_full_model_as_avl(z3,AVL) :- !, |
198 | | % get and parse the full model |
199 | | smt_solver_interface_call(z3,get_full_model_string(FullModel)), |
200 | | %format('z3 full model:~n~w~n',[FullModel]), |
201 | ? | z3_model_to_avl(FullModel,AVL). |
202 | | get_full_model_as_avl(_,AVL) :- empty_avl(AVL). |
203 | | |
204 | | map_translate_z3_predicate([], _, Acc, Acc). |
205 | | map_translate_z3_predicate([Z3Pred|T], Env, Acc, Preds) :- |
206 | ? | translate_z3_predicate(Z3Pred, Env, Pred), |
207 | ? | map_translate_z3_predicate(T, Env, [Pred|Acc], Preds). |
208 | | |
209 | | translate_z3_quantified_vars([], _, Acc, Acc). |
210 | | translate_z3_quantified_vars([[Name,Type]|T], Env, Acc, Preds) :- |
211 | | z3_type_to_b_type(Type,BType), |
212 | | Id = b(identifier(Name),BType,[]), |
213 | | translate_z3_quantified_vars(T, Env, [Id|Acc], Preds). |
214 | | |
215 | | % translate a z3 predicate to a B AST predicate |
216 | | translate_z3_predicate([not,Left], Env, Res) :- |
217 | | !, |
218 | | translate_z3_predicate(Left, Env, TL), |
219 | | create_negation(TL,Res). |
220 | | translate_z3_predicate([ZOP|T], Env, Res) :- |
221 | | z3_connective_to_b(ZOP, BOP), |
222 | | !, |
223 | ? | translate_z3_connective(BOP, T, Env, Res). |
224 | | translate_z3_predicate([let,[[Id,Val]],Function], Env, Res) :- |
225 | | !, |
226 | | z3_replace_let_id_by_value(Id, Val, Function, NewFunction), |
227 | ? | translate_z3_predicate(NewFunction, Env, Res). |
228 | | translate_z3_predicate([let,[[Id,Val]|T],Function], Env, Res) :- |
229 | | !, |
230 | | T \== [], |
231 | | z3_replace_let_id_by_value(Id, Val, Function, NewFunction), |
232 | | translate_z3_predicate([let,T,NewFunction], Env, Res). |
233 | | translate_z3_predicate([=,Left,Right], Env, Res) :- |
234 | | !, |
235 | | typecheck_for_global_type(Left, Right, Env, Type), |
236 | ? | translate_z3_expr(Left, Env, Type, TL), |
237 | ? | translate_z3_expr(Right, Env, Type, TR), |
238 | | create_equality(TL,TR,Res). |
239 | | translate_z3_predicate([ZOP,Left,Right], Env, Res) :- |
240 | | z3_integer_comparison(ZOP, BOP), |
241 | | !, |
242 | | translate_z3_expr(Left, Env, IntegerOrReal, TL), |
243 | | translate_z3_expr(Right, Env, IntegerOrReal, TR), |
244 | | Pred =.. [BOP,TL,TR], |
245 | | safe_create_texpr(Pred,pred,Res). |
246 | | translate_z3_predicate([select,Array,Entry], Env, Res) :- |
247 | | !, |
248 | | translate_z3_expr(Array, Env, _, BSet), |
249 | ? | translate_z3_expr(Entry, Env, _, BEntry), |
250 | | Res = b(member(BEntry,BSet),pred,[]). |
251 | | translate_z3_predicate([exists,Vars,[Body]], Env, Res) :- |
252 | | translate_z3_quantified_vars(Vars, Env, [], BVars), |
253 | | Env = env(Ids,AVL), |
254 | | append(Ids, BVars, NewIds), |
255 | ? | translate_z3_predicate(Body, env(NewIds,AVL), BBody), |
256 | | !, |
257 | | find_identifier_uses(BBody, [], UsedIds), |
258 | | Res = b(exists(BVars,BBody),pred,[used_ids(UsedIds)]). |
259 | | translate_z3_predicate([exists,Vars,Body], Env, Res) :- |
260 | | translate_z3_quantified_vars(Vars, Env, [], BVars), |
261 | | Env = env(Ids,AVL), |
262 | | append(Ids, BVars, NewIds), |
263 | | translate_z3_predicate(Body, env(NewIds,AVL), BBody), |
264 | | !, |
265 | | find_identifier_uses(BBody, [], UsedIds), |
266 | | Res = b(exists(BVars,BBody),pred,[used_ids(UsedIds)]). |
267 | | translate_z3_predicate([forall,Vars,[Body]], Env, Res) :- |
268 | | translate_z3_quantified_vars(Vars, Env, [], BVars), |
269 | | Env = env(Ids,AVL), |
270 | | append(Ids, BVars, NewIds), |
271 | | translate_z3_predicate(Body, env(NewIds,AVL), BBody), |
272 | | !, |
273 | | find_identifier_uses(BBody, [], UsedIds), |
274 | | get_typing_predicates(BVars, TypingPredList), |
275 | | conjunct_predicates(TypingPredList, TypingPred), |
276 | | Res = b(forall(BVars,TypingPred,BBody),pred,[used_ids(UsedIds)]). |
277 | | translate_z3_predicate([forall,Vars,Body], Env, Res) :- |
278 | | translate_z3_quantified_vars(Vars, Env, [], BVars), |
279 | | Env = env(Ids,AVL), |
280 | | append(Ids, BVars, NewIds), |
281 | | translate_z3_predicate(Body, env(NewIds,AVL), BBody), |
282 | | !, |
283 | | find_identifier_uses(BBody, [], UsedIds), |
284 | | get_typing_predicates(BVars, TypingPredList), |
285 | | conjunct_predicates(TypingPredList, TypingPred), |
286 | | Res = b(forall(BVars,TypingPred,BBody),pred,[used_ids(UsedIds)]). |
287 | | translate_z3_predicate([ite, Test, Left, Right], Env, Res) :- !, |
288 | | translate_z3_predicate(Test,Env, BTest), |
289 | ? | translate_z3_predicate(Left, Env, BThen), |
290 | ? | translate_z3_predicate(Right,Env, BElse), |
291 | | safe_create_texpr(convert_bool(BThen),boolean,BThenBool), |
292 | | safe_create_texpr(convert_bool(BElse),boolean,BElseBool), |
293 | | safe_create_texpr(if_then_else(BTest,BThenBool,BElseBool),boolean,TRes), |
294 | | Res = b(equal(TRes,b(boolean_true,boolean,[])),pred,[]). |
295 | | translate_z3_predicate(In, Env, Res) :- |
296 | | translate_z3_expr(In, Env, boolean, TRes), |
297 | | !, |
298 | | % expr to pred |
299 | | Res = b(equal(TRes,b(boolean_true,boolean,[])),pred,[]). |
300 | | translate_z3_predicate(Pred,_,_) :- |
301 | | add_error_fail(translate_z3_predicate, 'Missing translation for Z3 predicate:', Pred). |
302 | | |
303 | | % see also smt_id_to_prob_id_preds in smtlib_solver |
304 | | z3_connective_to_b(and, conjunct). |
305 | | z3_connective_to_b(or, disjunct). |
306 | | z3_connective_to_b('=>', implication). |
307 | | |
308 | | % see also smt_id_to_prob_id in smtlib_solver |
309 | | z3_integer_comparison(<=, less_equal). |
310 | | z3_integer_comparison(<, less). |
311 | | z3_integer_comparison(>, greater). % not used ? |
312 | | z3_integer_comparison(>=, greater_equal). % not used ? |
313 | | |
314 | | %% create_nested_binary_expr(+BOP, +Env, +Type, +TypeA, +TypeB, Args, BExpr). |
315 | | % Z3 model might contain for instance [*,x,x,x] which needs to |
316 | | % be nested using binary operators in B. |
317 | | create_nested_binary_expr(BOP, Env, Type, TA, TB, [Arg1,Arg2|T], Expr) :- |
318 | | translate_z3_expr(Arg1, Env, TA, TArg1), |
319 | | get_texpr_type(TArg1, TA), |
320 | ? | translate_z3_expr(Arg2, Env, TB, TArg2), |
321 | | get_texpr_type(TArg2, TB), |
322 | | TExpr =.. [BOP,TArg1,TArg2], |
323 | | Acc = b(TExpr,Type,[]), |
324 | ? | create_nested_binary_expr(BOP, Env, Type, TA, TB, Acc, T, Expr). |
325 | | |
326 | | create_nested_binary_expr(_, _, _, _, _, Acc, [], Acc). |
327 | | create_nested_binary_expr(BOP, Env, Type, _, TB, Acc, [Arg], Expr) :- |
328 | | !, |
329 | | translate_z3_expr(Arg, Env, TB, TArg), |
330 | | TExpr =.. [BOP,Acc,TArg], |
331 | | Expr = b(TExpr,Type,[]). |
332 | | create_nested_binary_expr(BOP, Env, Type, TA, TB, Acc, [Arg|T], Expr) :- |
333 | | translate_z3_expr(Arg, Env, TA, TArg), |
334 | | TExpr =.. [BOP,Acc,TArg], |
335 | | NAcc = b(TExpr,Type,[]), |
336 | | create_nested_binary_expr(BOP, Env, Type, TA, TB, NAcc, T, Expr). |
337 | | |
338 | | map_translate_z3_expr([], _, Acc, Acc). |
339 | | map_translate_z3_expr([Z3Pred|T], Env, Acc, Preds) :- |
340 | ? | translate_z3_expr(Z3Pred, Env, _, Pred), |
341 | ? | map_translate_z3_expr(T, Env, [Pred|Acc], Preds). |
342 | | |
343 | | handle_globalsets_fdrange_contradiction(Z3sResNumber,Set) :- |
344 | | get_user_defined_scope(Set,Low,Up,Span),!, |
345 | | DeferredSetSize is 1+Up-Low, |
346 | | Z3sResNumber > DeferredSetSize, |
347 | | add_error(translate_z3_expr_globalsets_fdrange, |
348 | | 'Z3\'s solution contradicts the size set for the deferred set. Try to increase the set size by adapting the DEFINITION or -card command-line argument.', |
349 | | z3:Z3sResNumber:Set:DeferredSetSize,Span), |
350 | | fail. |
351 | | handle_globalsets_fdrange_contradiction(Z3sResNumber,_Set) :- |
352 | | get_preference(globalsets_fdrange, DeferredSetSize), |
353 | | ( Z3sResNumber > DeferredSetSize |
354 | | -> % Z3 does not consider globalsets_fdrange; its solution might contradict ProB's preference |
355 | | add_error_fail(translate_z3_expr_globalsets_fdrange, |
356 | | 'Z3\'s solution contradicts ProB\'s preference DEFAULT_SETSIZE. Try to increase the preference.', |
357 | | z3:Z3sResNumber:'DEFAULT_SETSIZE':DeferredSetSize) |
358 | | ; % this is any other bug and should not happen |
359 | | fail |
360 | | ). |
361 | | |
362 | | % translate a z3 expression to a B AST expression |
363 | | %translate_z3_expr(Pred,E,T,_) :- print(translate_z3_expr(Pred,E,T)),nl,fail. |
364 | | translate_z3_expr(['-',Number],_,integer,Res) :- |
365 | | !, |
366 | | Number1 is -Number, |
367 | | Res=b(integer(Number1),integer,[]). |
368 | | translate_z3_expr(Int,_,integer,Res) :- integer(Int),!, Res=b(integer(Int),integer,[]). |
369 | | translate_z3_expr(true,_,boolean,Res) :- !, Res=b(boolean_true,boolean,[]). |
370 | | translate_z3_expr(false,_,boolean,Res) :- !, Res=b(boolean_false,boolean,[]). |
371 | | translate_z3_expr([ZOP|T], Env, boolean, Res) :- |
372 | | z3_connective_to_b(ZOP, BOP), |
373 | | !, |
374 | | translate_z3_connective(BOP, T, Env, PredRes), |
375 | | Res = b(convert_bool(PredRes),boolean,[]). |
376 | | translate_z3_expr(['-',RealAtom], Env, real, Res) :- |
377 | | atom(RealAtom), |
378 | | atom_concat('-', RealAtom, NRealAtom), |
379 | | translate_z3_expr(NRealAtom, Env, real, Res). |
380 | | translate_z3_expr(Atom, _, Type, Res) :- |
381 | | atom(Atom), |
382 | ? | virtual_deferred_set_id(Atom, FdVar), |
383 | | FdVar = fd(_,DefSet), |
384 | | Type = global(DefSet), |
385 | | !, |
386 | | Res = b(value(FdVar),Type,[]). |
387 | | translate_z3_expr(Atom, _, Type, Res) :- |
388 | | atom(Atom), |
389 | | ( ( split_atom(Atom,['!'],Splitted), |
390 | | Splitted = [Set,val,InternalNumber] |
391 | | ) |
392 | | -> Type = global(Set), |
393 | | !, |
394 | | convert_to_number(InternalNumber,Nr), |
395 | | ResNumber is Nr + 1, |
396 | | Val = fd(ResNumber,Set), |
397 | | asserta(fd_var_of_z3(Set,ResNumber)), |
398 | | ( global_type(Val,Set) |
399 | | -> true |
400 | | ; handle_globalsets_fdrange_contradiction(ResNumber,Set) |
401 | | ), |
402 | | safe_create_texpr(value(Val), global(Set), Res) |
403 | | ; % atom could represent a real number |
404 | | Type = real, |
405 | ? | atom_to_number(Atom, Real), |
406 | | float(Real), !, |
407 | | safe_create_texpr(real(Atom), real, Res) |
408 | | ). |
409 | | translate_z3_expr(Nr,_,global(GS),Res) :- number(Nr),!, % Z3 represents first element of GS by 0, ... |
410 | | Nr1 is Nr+1, Val = fd(Nr1,GS), |
411 | | asserta(fd_var_of_z3(GS,Nr1)), |
412 | | ( global_type(Val,GS) |
413 | | -> true |
414 | | ; handle_globalsets_fdrange_contradiction(Nr1,GS) |
415 | | ), |
416 | | safe_create_texpr(value(Val), global(GS), Res). |
417 | | translate_z3_expr([Couple,A,B],Env,couple(T1,T2),b(couple(AT,BT),couple(T1,T2),[])) :- |
418 | | atom(Couple), |
419 | ? | get_couple_type_from_atom(Couple, T1, T2), |
420 | ? | translate_z3_expr(A, Env, T1, AT), |
421 | ? | translate_z3_expr(B, Env, T2, BT). |
422 | | translate_z3_expr([CouplePrj,Arg], Env, Type, Res) :- |
423 | | atom(CouplePrj), |
424 | | translate_z3_expr(Arg, Env, _, RArg), |
425 | | get_texpr_type(RArg, CType), |
426 | | ( atom_prefix('get_x_couple', CouplePrj), |
427 | | PrjNode = first_of_pair(RArg), |
428 | | CType = couple(ResType,_) |
429 | | ; atom_prefix('get_y_couple', CouplePrj), |
430 | | PrjNode = second_of_pair(RArg), |
431 | | CType = couple(_,ResType) |
432 | | ), |
433 | | !, |
434 | | Type = ResType, |
435 | | safe_create_texpr(PrjNode, ResType, Res). |
436 | | translate_z3_expr(Id, env(Env,_AVL), Type, Res) :- |
437 | | atom(Id), |
438 | | TId = b(identifier(Id),Type,_), |
439 | ? | member(TId, Env), |
440 | | !, |
441 | | Res = TId. |
442 | | translate_z3_expr(Id, _, Type, Res) :- |
443 | | atom(Id), |
444 | | Type = global(_), |
445 | | % global ids which are not in the environment |
446 | | !, |
447 | | safe_create_texpr(identifier(Id), Type, Res). |
448 | | translate_z3_expr(CstFunc,env(Env,AVL),Type,CompSet) :- atom(CstFunc), |
449 | | Type = set(couple(PType,RType)), |
450 | | avl_fetch(CstFunc,AVL,'z3-define-fun'([[ParamName,ParameterType]],ReturnType,BodyTree)), |
451 | | z3_type_to_b_type(ParameterType,PType), % check if type matches |
452 | | z3_type_to_b_type(ReturnType,RType), % ditto |
453 | | !, |
454 | | PID = b(identifier(ParamName),PType,[]), |
455 | | %print(translate_body(CstFunc,PID)),nl, |
456 | | translate_z3_expr(BodyTree,env([PID|Env],AVL),RType,BodyExpr), |
457 | | %print(body(CstFunc)),translate:print_bexpr(BodyExpr),nl, |
458 | | unique_typed_id("lambda",RType,LambdaID), |
459 | | create_equality(LambdaID,BodyExpr,CPred), |
460 | | % {PID,lambda | lambda = BodyExpr} |
461 | | safe_create_texpr(comprehension_set([PID,LambdaID],CPred), set(couple(PType,RType)), CompSet). |
462 | | translate_z3_expr([CstFunc,Arg],env(Env,AVL),Type,Res) :- % function application |
463 | | avl_fetch(CstFunc,AVL,'z3-define-fun'([[ParamID,ParameterType]],ReturnType,BodyTree)), |
464 | | z3_type_to_b_type(ReturnType,Type), % check if type matches |
465 | | !, |
466 | | ( ParamID == Arg % special case if argument and parameter identical |
467 | | -> translate_z3_expr(BodyTree,env(Env,AVL),Type,Res) |
468 | | ; z3_type_to_b_type(ParameterType,PType), % TO DO: couple-> ground type; PType could be not ground ! |
469 | | translate_z3_expr(CstFunc,env(Env,AVL),set(couple(PType,Type)),TFun), |
470 | | translate_z3_expr(Arg,env(Env,AVL),PType,TArg), |
471 | | create_texpr(function(TFun,TArg),Type,[contains_wd_condition],Res) |
472 | | ). |
473 | | translate_z3_expr([let,[[Id,Val]],Function],Env,Type,Res) :- !, |
474 | | z3_replace_let_id_by_value(Id,Val,Function,NewFunction), |
475 | ? | translate_z3_expr(NewFunction,Env,Type,Res). |
476 | | translate_z3_expr([let,[[Id,Val]|T],Function],Env,Type,Res) :- |
477 | | T \== [], |
478 | | z3_replace_let_id_by_value(Id,Val,Function,NewFunction), |
479 | | translate_z3_expr([let,T,NewFunction],Env,Type,Res). |
480 | | translate_z3_expr([ZOP, Left], Env, Type,Res) :- |
481 | | z3_unary_expr_to_b(ZOP, BOP, Type),!, |
482 | | translate_z3_expr(Left, Env, Type, TL), |
483 | | Expr =.. [BOP,TL], |
484 | | safe_create_texpr(Expr, Type, Res). |
485 | | translate_z3_expr([ZOP|Args], Env, Type, Res) :- |
486 | | % operators such as multiplication can have an arbitrary arity like [*,x,x,x] |
487 | ? | z3_binary_expr_to_b(ZOP, BOP, TA, TB, Type), !, |
488 | ? | create_nested_binary_expr(BOP, Env, Type, TA, TB, Args, Res). |
489 | | translate_z3_expr([ite, Test, Left, Right], Env, Type, Res) :- !, |
490 | | translate_z3_predicate(Test,Env, BTest), |
491 | ? | translate_z3_expr(Left, Env, Type, BThen), |
492 | ? | translate_z3_expr(Right,Env, Type, BElse), get_texpr_type(BThen,Type), |
493 | | safe_create_texpr(if_then_else(BTest,BThen,BElse),Type,Res). |
494 | | translate_z3_expr(String,_,string,Res) :- |
495 | | atom(String), |
496 | | !, |
497 | | Res = b(string(String),string,[]). |
498 | | translate_z3_expr(['_','as-array',AuxFunName],_,set(X),Res) :- !, |
499 | | % set is represented by aux function |
500 | | translate_z3_expr_using_full_model(AuxFunName,set(couple(X,boolean)),ChFunSet), |
501 | | % we computed the characteristic function of the set; now convert it to a set |
502 | | % Now we need to compute dom(ChFunSet |> {TRUE}) = ChFunSet~[{TRUE}] = {x|ChFunSet(x)=TRUE} |
503 | | unique_typed_id("el!",X,Element), |
504 | | create_texpr(function(ChFunSet,Element),boolean,[contains_wd_condition],FCall), |
505 | | create_equality(b(boolean_true,boolean,[]),FCall,NewNewPred), |
506 | | safe_create_texpr(comprehension_set([Element],NewNewPred),set(X),CompSet), |
507 | | % translate:print_bexpr(CompSet),nl, |
508 | | compute_bcomp_set(CompSet,Set), |
509 | | Res = b(value(Set),set(X),[]). |
510 | | translate_z3_expr([store,Sub,Entry,TStoreRes],Env,set(Type),Res) :- |
511 | | % TStoreRes can be true, false or a predicate which needs to be evaluated first |
512 | | translate_z3_expr(Sub,Env,set(Type),S1), |
513 | ? | translate_z3_expr(Entry,Env,Type,El2), |
514 | | S2 = b(set_extension([El2]),set(Type),[]), |
515 | | ( (TStoreRes = true; TStoreRes = false) |
516 | | -> StoreRes = TStoreRes |
517 | | ; translate_z3_predicate(TStoreRes, Env, BStoreRes), |
518 | | ( b_test_boolean_expression_cs(BStoreRes, [], [],'translating Z3 value',0) |
519 | | -> StoreRes = true |
520 | | ; StoreRes = false |
521 | | ) |
522 | | ), |
523 | | ( StoreRes = true |
524 | | -> Expr = union(S1,S2) |
525 | | ; StoreRes = false, |
526 | | Expr = set_subtraction(S1,S2) |
527 | | ), |
528 | | !, |
529 | | b_compute_expression_nowf(b(Expr,set(Type),[]), [], [], List,'translating Z3 value',0), |
530 | | Res = b(value(List),set(Type),[]). |
531 | | translate_z3_expr([[as,const,['Array',Z3Type,'Bool']],false],_,Type,b(value([]),Type,[])) :- |
532 | | ( (Type = set(BType), z3_type_to_b_type(Z3Type,BType)) |
533 | | -> true |
534 | | ; add_error(translate_z3_expr,'Unexpected type in Z3 model: ',types(Z3Type,Type)) |
535 | | ), |
536 | | !. |
537 | | translate_z3_expr([[as,const,['Array',Z3Type,'Bool']],true],_,Type,b(value(Res),Type,[])) :- |
538 | | ( (Type = set(BType), z3_type_to_b_type(Z3Type,BType)) |
539 | | -> b_type2_set(BType,Res), |
540 | | ! |
541 | | ; add_error(translate_z3_expr,'Unexpected type in Z3 model: ',types(Z3Type,Type)), |
542 | | fail |
543 | | ). |
544 | | translate_z3_expr(['record'|Z3Fields],Env,record(Fields),b(rec(FieldsOut),record(Fields),[])) :- |
545 | | maplist(translate_z3_record(Env),Fields,Z3Fields,FieldsOut). |
546 | | translate_z3_expr([iteration,Rel,Int],Env,set(CoupleType),Res) :- |
547 | | translate_z3_expr(Rel,Env,set(CoupleType),TRel), |
548 | | translate_z3_expr(Int,Env,integer,BInt), |
549 | | Iteration = b(iteration(TRel,BInt),set(CoupleType),[]), |
550 | | ( BInt = b(integer(_),_,_) |
551 | | -> compute_bcomp_set(Iteration,Set), |
552 | | Res = b(value(Set),set(CoupleType),[]) |
553 | | ; Res = Iteration |
554 | | ). |
555 | | % Some special cases to improve lambda translations |
556 | | translate_z3_expr([lambda,[[ClosureVar,ClosureVarType]],Body],Env,SetType,Res) :- |
557 | | ( ClosureVar = refl_closure_g_u_var |
558 | | -> Functor = reflexive_closure |
559 | | ; ClosureVar = closure_g_u_var, |
560 | | Functor = closure |
561 | | ), |
562 | | !, |
563 | | z3_type_to_b_type(ClosureVarType,BType), |
564 | | TClosureVar = b(identifier(ClosureVar),BType,[]), |
565 | | % compute closure with ProB if Z3 does not unfold lambda, |
566 | | % the translated model itself (lambda(exists(...))) is too complex so we catch translated closures here |
567 | | Env = env(Ids,B), |
568 | | translate_z3_predicate(Body, env([TClosureVar|Ids],B), TBody), |
569 | | TBody = b(exists(_,ExistsBody),pred,_), |
570 | | conjunction_to_list(ExistsBody, ExistsBodyConj), |
571 | | member(b(exists(_,ExistsBody2),pred,_), ExistsBodyConj), |
572 | | conjunction_to_list(ExistsBody2, ExistsBodyConj2), |
573 | | member(b(equal(b(identifier(_),SetType,_),b(iteration(TRel,_),SetType,_)),pred,[]), ExistsBodyConj2), |
574 | | !, |
575 | | BNode =.. [Functor,TRel], |
576 | | TRes = b(BNode,SetType,[]), |
577 | | clean_up(TRes, [], Res). |
578 | | translate_z3_expr([lambda,Args,Body],env(Ids,_),set(BType),Res) :- |
579 | | % see for instance ':z3-double-check f = %x.(x : INTEGER|x * x * x) & f(f(x)) = y & y = 512' |
580 | | Args = [[ID,Z3Type]], |
581 | | z3_type_to_b_type(Z3Type,BType), |
582 | | TID = b(identifier(ID),BType,[]), |
583 | | Body = [exists|_], |
584 | | translate_z3_predicate(Body,env([TID|Ids],empty),TBody), |
585 | | TBody = b(exists([LambdaID],ExistsBody),pred,_), |
586 | | conjunction_to_list(ExistsBody, ExistsList), |
587 | | select(ExistsBody, ExistsList, RestExistsList), |
588 | | ExistsBody = b(equal(CoupleCst,ExistCouple),pred,_), |
589 | | CoupleCst = b(identifier('_couple_cst'),couple(_,_),_), |
590 | | conjunct_predicates(RestExistsList, RestExistsBody), |
591 | | !, |
592 | | ExistCouple = b(couple(_,ExistsExpr),_,_), |
593 | | safe_create_texpr(lambda([LambdaID],RestExistsBody,ExistsExpr), set(BType), BLambda), |
594 | | clean_up(BLambda, [], CompSet), |
595 | | compute_bcomp_set(CompSet,Set), |
596 | | Res = b(value(Set),set(BType),[]). |
597 | | translate_z3_expr([lambda,Args,Body],env(Ids,B),set(BType),Res) :- |
598 | | Args = [[ID,Z3Type]], % TO DO: more than one argument? |
599 | | z3_type_to_b_type(Z3Type,BType), |
600 | | !, |
601 | | TID = b(identifier(ID),BType,[]), |
602 | ? | translate_z3_predicate(Body,env([TID|Ids],B),TBody), |
603 | | safe_create_texpr(comprehension_set([TID],TBody),set(BType),CompSet), |
604 | | %print('lambda: '),translate:print_bexpr(CompSet),nl, print(CompSet),nl, |
605 | | compute_bcomp_set(CompSet,Set), |
606 | | Res = b(value(Set),set(BType),[]). |
607 | | % |
608 | | translate_z3_expr([['_',map,AndOrTerm]|T], Env, _, Res) :- |
609 | | ( AndOrTerm = [AndOr,['Bool','Bool'],'Bool'] % prior version 4.12.2 |
610 | | ; AndOrTerm = AndOr % since version 4.12.2 |
611 | | ), |
612 | | ( AndOr == and |
613 | | ; AndOr == or |
614 | | ), |
615 | | !, |
616 | ? | map_translate_z3_expr(T, Env, [], TT), |
617 | | TT = [b(_,SetType,_)|_], |
618 | | ( AndOr == and |
619 | | -> unfold_general_intersection(TT, SetType, Res) |
620 | | ; unfold_general_union(TT, SetType, Res) |
621 | | ). |
622 | | translate_z3_expr([mod,A,B], Env, integer, Res) :- |
623 | | !, |
624 | | translate_z3_expr(A, Env, integer, BA), |
625 | | translate_z3_expr(B, Env, integer, BB), |
626 | | BIsZero = b(equal(BB,b(integer(0),integer,[])),pred,[]), |
627 | | % return 0 if B is zero, otherwise (= (mod x y) (- x (* y (div x y)))) holds |
628 | | ModEq = b(minus(BA,b(multiplication(BB, |
629 | | b(floored_div(BA,BB),integer,[contains_wd_condition])),integer,[contains_wd_condition])), |
630 | | integer,[contains_wd_condition]), |
631 | | safe_create_texpr(if_then_else(BIsZero,b(integer(0),integer,[]),ModEq),integer,TRes), |
632 | | clean_up(TRes, [], Res). |
633 | | translate_z3_expr([rem,A,B], Env, integer, Res) :- |
634 | | !, |
635 | | translate_z3_expr(A, Env, integer, BA), |
636 | | translate_z3_expr(B, Env, integer, BB), |
637 | | BIsZero = b(equal(BB,b(integer(0),integer,[])),pred,[]), |
638 | | BLowerZero = b(less(BB,b(integer(0),integer,[])),pred,[]), |
639 | | % return 0 if B is zero, otherwise (= (rem x y) (ite (< y 0) (* (- x (* y (div x y))) -1) (- x (* y (div x y))))) holds |
640 | | ModEq = b(minus(BA,b(multiplication(BB, |
641 | | b(floored_div(BA,BB),integer,[contains_wd_condition])),integer,[contains_wd_condition])), |
642 | | integer,[contains_wd_condition]), |
643 | | safe_create_texpr(if_then_else(BLowerZero,b(unary_minus(ModEq),integer,[]),ModEq),integer,IfExpr), |
644 | | safe_create_texpr(if_then_else(BIsZero,b(integer(0),integer,[]),IfExpr),integer,TRes), |
645 | | clean_up(TRes, [], Res). |
646 | | translate_z3_expr(Expr,_,Type,_) :- |
647 | | \+ check_error_occured(translate_z3_expr_globalsets_fdrange, _), |
648 | | add_error_fail(translate_z3_expr, 'Missing translation for Z3 expression:', Expr:Type). |
649 | | |
650 | | translate_z3_connective(BOP, T, Env, PredRes) :- |
651 | ? | map_translate_z3_predicate(T, Env, [], NT), |
652 | | ( BOP == conjunct |
653 | | -> conjunct_predicates(NT, PredRes) |
654 | | ; BOP == disjunct |
655 | | -> disjunct_predicates(NT, PredRes) |
656 | | ; Pred =.. [BOP|NT], |
657 | | safe_create_texpr(Pred, pred, PredRes) |
658 | | ). |
659 | | |
660 | | unfold_general_intersection([A], _, A). |
661 | | unfold_general_intersection([A,B|T], SetType, Res) :- |
662 | | !, |
663 | | Acc = b(intersection(A,B),SetType,[]), |
664 | | unfold_general_intersection_acc(T, SetType, Acc, Res). |
665 | | |
666 | | unfold_general_intersection_acc([], _, Acc, Acc). |
667 | | unfold_general_intersection_acc([A,B|T], SetType, Acc, Res) :- |
668 | | NewAcc = b(intersection(Acc,b(intersection(A,B),SetType,[])),SetType,[]), |
669 | | unfold_general_intersection_acc(T, SetType, NewAcc, Res). |
670 | | |
671 | | unfold_general_union([A], _, A). |
672 | | unfold_general_union([A,B|T], SetType, Res) :- |
673 | | !, |
674 | | Acc = b(union(A,B),SetType,[]), |
675 | | unfold_general_union_acc(T, SetType, Acc, Res). |
676 | | |
677 | | unfold_general_union_acc([], _, Acc, Acc). |
678 | | unfold_general_union_acc([A,B|T], SetType, Acc, Res) :- |
679 | | NewAcc = b(union(Acc,b(union(A,B),SetType,[])),SetType,[]), |
680 | | unfold_general_union_acc(T, SetType, NewAcc, Res). |
681 | | |
682 | | z3_unary_expr_to_b('-',unary_minus ,integer). |
683 | | |
684 | | |
685 | | % z3_binary_expr_to_b(Z3Op,BOp,TypeLeftArg,TypeRightArg,TypeOfExpr) |
686 | | z3_binary_expr_to_b('*', multiplication, integer, integer, integer). |
687 | | z3_binary_expr_to_b('+', add, integer, integer, integer). |
688 | | z3_binary_expr_to_b('-', minus, integer, integer, integer). |
689 | | z3_binary_expr_to_b('/', floored_div, integer, integer, integer). |
690 | | z3_binary_expr_to_b('div', floored_div, integer, integer, integer). |
691 | | z3_binary_expr_to_b(Z3Couple, couple, TA, TB, couple(TA,TB)) :- |
692 | | atom(Z3Couple), |
693 | | atom_prefix('couple', Z3Couple). |
694 | | |
695 | | % -------------------- |
696 | | |
697 | | z3_ground_result(real,real(0.0)). |
698 | | z3_ground_result(integer,int(0)). |
699 | | z3_ground_result(boolean,pred_true). |
700 | | z3_ground_result(couple(X,Y),(XG,YG)) :- |
701 | | z3_ground_result(X,XG), z3_ground_result(Y,YG). |
702 | | z3_ground_result(set(_),[]). |
703 | | z3_ground_result(record(Fields),rec(FieldsOut)) :- |
704 | | maplist(z3_ground_record_fields,Fields,FieldsOut). |
705 | | |
706 | | z3_ground_record_fields(field(Name,BType),field(Name,BVal)) :- |
707 | | z3_ground_result(BType,BVal). |
708 | | |
709 | | % -------------------- |
710 | | |
711 | | compute_bcomp_set(CompSet,ResultOut) :- |
712 | | % translate:set_unicode_mode,translate:print_bexpr(CompSet), |
713 | | b_compute_expression_nowf(CompSet,[],[],Res,'translating Z3 value',0), |
714 | | (try_expand_custom_set_to_list(Res,ResultOut,true,z3_set_to_b_set) |
715 | | -> true |
716 | | ; ResultOut = Res). |
717 | | |
718 | | atom_to_term(Atom, Term) :- |
719 | | atom_concat(Atom, '.', AtomWithStop), |
720 | | atom_codes(AtomWithStop, AtomWithStopC), |
721 | | read_from_codes(AtomWithStopC, Term). |
722 | | |
723 | | z3_type_to_b_type(record, Type) :- !, Type =.. [record|_]. % record type in SMT-LIB is just 'record' |
724 | | z3_type_to_b_type('String', Type) :- !, Type = string. |
725 | | z3_type_to_b_type('Int', Type) :- !, Type = integer. |
726 | | z3_type_to_b_type('Bool', Type) :- !, Type = boolean. |
727 | | z3_type_to_b_type('Real', Type) :- !, Type = real. |
728 | | z3_type_to_b_type(Z3Couple, BType) :- |
729 | | atom(Z3Couple), |
730 | ? | get_couple_type_from_atom(Z3Couple, CoupleType1, CoupleType2), |
731 | | !, |
732 | | BType = couple(CoupleType1,CoupleType2). |
733 | | z3_type_to_b_type(GlobalSet, BType) :- |
734 | ? | b_global_set(GlobalSet), |
735 | | !, |
736 | | BType = global(GlobalSet). |
737 | | z3_type_to_b_type(['Array',SetType,'Bool'], BType) :- |
738 | | !, |
739 | | z3_type_to_b_type(SetType, BSetType), |
740 | | BType = set(BSetType). |
741 | | z3_type_to_b_type(A, _) :- |
742 | | add_error_fail(z3_type_to_b_type, "Missing translation for Z3 type in model translation.", [A]). |
743 | | |
744 | | get_couple_type_from_atom(CoupleAtom, CoupleType1, CoupleType2) :- |
745 | | atom(CoupleAtom), |
746 | | atom_codes(CoupleAtom, Codes), |
747 | ? | get_couple_type_from_codes([TT1,TT2], Codes, []), |
748 | | atom_codes(T1Atom, TT1), |
749 | | atom_to_term(T1Atom, CoupleType1), |
750 | | atom_codes(T2Atom, TT2), |
751 | | atom_to_term(T2Atom, CoupleType2). |
752 | | |
753 | | get_couple_type_from_codes([T1,T2]) --> |
754 | | "couple(", |
755 | ? | type_symbol(T1), |
756 | | ",", |
757 | ? | type_symbol(T2), |
758 | | ")". |
759 | | |
760 | | z3_replace_let_id_by_value_maplist([], _, _, Res) :- !, Res=[]. |
761 | | z3_replace_let_id_by_value_maplist([let,LetVals|T], Id, _, Out) :- |
762 | | % prevent that the let ids of a nested let expression are mistakenly replaced |
763 | | % I.e., Id is now being overwritten by another let; |
764 | | % TODO: but what if Id is used in RHS of some LetVals? Can that be? |
765 | | member([Id,_], LetVals), |
766 | | !, |
767 | | Out = [let,LetVals|T]. |
768 | | z3_replace_let_id_by_value_maplist([H|T], Id, Val, [NH|NT]) :- |
769 | | z3_replace_let_id_by_value(Id, Val, H, NH), |
770 | | z3_replace_let_id_by_value_maplist(T, Id, Val, NT). |
771 | | |
772 | | |
773 | | z3_replace_let_id_by_value(Id,Val,Function,NewFunction) :- |
774 | | Function = [_|_], % is_list(Function), is_list also does a cyclic check |
775 | | !, |
776 | | z3_replace_let_id_by_value_maplist(Function,Id,Val,NewFunction). |
777 | | z3_replace_let_id_by_value(Id,Val,Function,NewFunction) :- |
778 | | ( Id = Function |
779 | | -> NewFunction = Val |
780 | | ; %atomic(Function), % do we need this test? |
781 | | NewFunction = Function |
782 | | ). |
783 | | |
784 | | z3_model_to_avl(FullModel,AVL) :- |
785 | | atom_codes(FullModel,Codes), |
786 | | %format('Full model:~n~s~n',[Codes]),nl, |
787 | | parse_lisp_style_expressions(E,Codes,[]),!, |
788 | ? | z3_lisp_to_avl(E,AVL). |
789 | | |
790 | | z3_lisp_to_avl(E,AVL) :- |
791 | | empty_avl(In), |
792 | ? | z3_lisp_to_avl(E,In,AVL). |
793 | | |
794 | | z3_lisp_to_avl([],A,A). |
795 | | z3_lisp_to_avl([['define-fun',Name,Param,Return,Tree]|T],AIn,AOut) :- |
796 | | avl_store(Name,AIn,'z3-define-fun'(Param,Return,Tree),ATemp), |
797 | ? | z3_lisp_to_avl(T,ATemp,AOut). |
798 | | % currently I think I do not need these facts... |
799 | | % as far as I understand they represent enumerated set Elements |
800 | | z3_lisp_to_avl([['declare-fun',_Name,_Params,_Type0]|T],AIn,AOut) :- |
801 | ? | z3_lisp_to_avl(T,AIn,AOut). |
802 | | % these occur for cardinality constraints |
803 | | z3_lisp_to_avl([['forall',_Vars,_Pred]|T],AIn,AOut) :- |
804 | ? | z3_lisp_to_avl(T,AIn,AOut). |
805 | | |
806 | | |
807 | | % ----------------------------- |
808 | | |
809 | | translate_cvc4_tree(['CONST_RATIONAL',Arg],integer,int(Val)) :- |
810 | | arg_is_number(Arg,Val). |
811 | | translate_cvc4_tree(['CONST_BOOLEAN',1],boolean,pred_true). |
812 | | translate_cvc4_tree(['CONST_BOOLEAN',0],boolean,pred_false). |
813 | | translate_cvc4_tree(['CONST_STRING',Content],string,string(Content)). |
814 | | translate_cvc4_tree(['SINGLETON',ValIn],set(X),[ValOut]) :- |
815 | | translate_cvc4_tree(ValIn,X,ValOut). |
816 | | translate_cvc4_tree(['EMPTYSET',emptyset,_Type],set(_),[]). |
817 | | translate_cvc4_tree(['TUPLE',V1,V2],couple(Type1,Type2),(TV1,TV2)) :- |
818 | | translate_cvc4_tree(V1,Type1,TV1), |
819 | | translate_cvc4_tree(V2,Type2,TV2). |
820 | | translate_cvc4_tree(['APPLY_CONSTRUCTOR','__cvc4_tuple_ctor',V1,V2],couple(Type1,Type2),(TV1,TV2)) :- |
821 | | translate_cvc4_tree(V1,Type1,TV1), |
822 | | translate_cvc4_tree(V2,Type2,TV2). |
823 | | translate_cvc4_tree(['UNION',V1,V2],set(X),Val) :- |
824 | | translate_cvc4_tree(V1,set(X),TV1), |
825 | | translate_cvc4_tree(V2,set(X),TV2), |
826 | | append(TV1,TV2,Val). |
827 | | translate_cvc4_tree(['UNINTERPRETED_CONSTANT',C],global(SId),fd(PBCId,SId)) :- |
828 | | atom_codes(C,CCodes), |
829 | | parse_uc(CId,CCodes,[]), |
830 | | PBCId is CId + 1. |
831 | | translate_cvc4_tree(['RECORD',_CVCRecordType|Fields],record(RFields),rec(FieldsOut)) :- |
832 | | maplist(translate_cvc4_record,RFields,Fields,FieldsOut). |
833 | | |
834 | | translate_cvc4_record(field(Name,BType),CVCVal,field(Name,BVal)) :- |
835 | | translate_cvc4_tree(CVCVal,BType,BVal). |
836 | | |
837 | | parse_uc(Id) --> |
838 | | "uc__SORT_TYPE_var_", number(_), |
839 | | "__", number(N), {number_codes(Id,N)}. |
840 | | |
841 | | parse_lisp_style_expressions(L) --> |
842 | | {reset_line_count}, |
843 | | lisp_style_expressions(L),!. |
844 | | |
845 | | lisp_style_expressions(Res) --> real_ws,!, |
846 | | lisp_style_expressions(Res). |
847 | | lisp_style_expressions([E|Es]) --> |
848 | | lisp_style_expression(E), !, |
849 | | lisp_style_expressions(Es). |
850 | | lisp_style_expressions([]) --> []. |
851 | | %lisp_style_expressions(_,In,_) :- linecount(Line), |
852 | | % format("lisp-style parser failed on line ~w on: ~s~n",[Line,In]),fail. |
853 | | |
854 | | |
855 | | closed_lisp_style_expressions(Res) --> real_ws,!, |
856 | | closed_lisp_style_expressions(Res). |
857 | | closed_lisp_style_expressions([]) --> ")",!. |
858 | | closed_lisp_style_expressions([E|Es]) --> |
859 | | lisp_style_expression(E), !, |
860 | | closed_lisp_style_expressions(Es). |
861 | | |
862 | | linecount(1). |
863 | | reset_line_count :- retractall(linecount(_)), assertz(linecount(1)). |
864 | | inc_linecount :- retract(linecount(Nr)), N1 is Nr+1, assertz(linecount(N1)). |
865 | | |
866 | | % real whitespace |
867 | | real_ws --> "\n", {inc_linecount},!, ws. |
868 | | real_ws --> [W], {W = 32 ; W = 10 ; W = 13}, !, ws. |
869 | | real_ws --> ";;", !, any_but_newline. |
870 | | |
871 | | % optional whitespace |
872 | | ws --> real_ws,!. |
873 | | ws --> []. |
874 | | any_but_newline --> [C], {C \= 10}, !, any_but_newline. |
875 | | any_but_newline -->"\n", {inc_linecount},!, ws. |
876 | | |
877 | | z3_op([42]) --> [42]. % * |
878 | | z3_op([43]) --> [43]. % + |
879 | | z3_op([45]) --> [45]. % - |
880 | | z3_op([47]) --> [47]. % / |
881 | | % TO DO: support all operators |
882 | | |
883 | | lisp_style_expression(Iteration) --> "((_ |iteration_", rel_type_skip, "| 0)", ws, |
884 | | closed_lisp_style_expressions([Arg1,Arg2]), ws, !, {Iteration = [iteration,Arg1,Arg2]}. |
885 | ? | lisp_style_expression(A) --> real(Cs), !, {atom_codes(A, Cs)}. |
886 | | lisp_style_expression(L) --> "!", !, ws, lisp_style_expression(L), ws, ":weight", ws, number(_). % optional term parameter |
887 | | lisp_style_expression(A) --> "/0", !, {A = '/0'}. % weird special case when using reals, e.g., for ':z3 a:REAL & b/=0.0 & a=1.2/b' a function called '/0' is defined |
888 | ? | lisp_style_expression(A) --> z3_op(Cs), !, {atom_codes(A, Cs)}. |
889 | ? | lisp_style_expression(A) --> typed_couple_top_level(Cs), !, {atom_codes(A, Cs)}. |
890 | | lisp_style_expression(A) --> non_empty_symbol(Cs), !, {atom_codes(A, Cs)}. |
891 | ? | lisp_style_expression(N) --> number(Cs), !, {number_codes(N, Cs)}. |
892 | | lisp_style_expression(N) --> "-", number(Cs), !, {number_codes(N2,Cs), N is -N2}. |
893 | ? | lisp_style_expression(A) --> string(Codes), !, {atom_codes(A,Codes)}. |
894 | | lisp_style_expression(List) --> "(", !, closed_lisp_style_expressions(List). |
895 | | lisp_style_expression(record_type(Fields)) --> |
896 | | "[#", !, ws, record_type_fields(Fields),!, |
897 | | ws, expect("#]",record_type). |
898 | | lisp_style_expression(_,In,_) :- In \= [], % not at end of string |
899 | | linecount(Line), |
900 | | format("lisp-style parser failed on line ~w on: ~s~n",[Line,In]),fail. |
901 | | |
902 | | expect(L,_) --> L,!. |
903 | | expect(L,Ctxt,In,_) :- linecount(Line), |
904 | | format("lisp-style parser failed on line ~w expecting ~s for ~w on: ~s~n",[Line,L,Ctxt, In]),fail. |
905 | | |
906 | | record_type_fields([F|Fields]) --> |
907 | | record_type_field(F), ws, expect(",",record_type_field), !, |
908 | | ws, record_type_fields(Fields). |
909 | | record_type_fields([F]) --> record_type_field(F). |
910 | | |
911 | | record_type_field(field(NameA,TypeA)) --> |
912 | | non_empty_symbol(Name), ":(TYPE_CONSTANT ", non_empty_symbol(Type), " type)", |
913 | | {atom_codes(NameA,Name),atom_codes(TypeA,Type)}. |
914 | | |
915 | | real(R) --> |
916 | ? | number(I), |
917 | | ".", |
918 | ? | number(D), |
919 | | ( "?", |
920 | | ! |
921 | | ; "" |
922 | | ), |
923 | | {append([I,[46],D],R)}. |
924 | | |
925 | ? | number([D|Ds]) --> digit(D), number(Ds). |
926 | | number([D]) --> digit(D). |
927 | | |
928 | | rel_type_skip --> |
929 | | "set(couple(", type_symbol(_), ",", type_symbol(_), "))". |
930 | | |
931 | | % top-level couple types are escaped with | in an SMT-Lib model |
932 | | typed_couple_top_level(Cs) --> |
933 | | "|couple(", |
934 | ? | in_couple(Cs1,Cs2), |
935 | | expect(")|", typed_couple_top_level), |
936 | | {append(["couple(",Cs1,",",Cs2,")"], Cs)}. |
937 | | |
938 | | typed_couple_inner(Cs) --> |
939 | | "couple(", |
940 | | in_couple(Cs1,Cs2), |
941 | | expect(")", typed_couple_inner), |
942 | | {append(["couple(",Cs1,",",Cs2,")"], Cs)}. |
943 | | |
944 | | in_couple(Cs1, Cs2) --> |
945 | ? | type_symbol(Cs1), !, |
946 | | expect(",", in_couple), |
947 | ? | type_symbol(Cs2). |
948 | | |
949 | | digit(D) --> [D], {48 =< D, D =< 57}. |
950 | | |
951 | ? | string(Codes) --> "\"", string_symbol(Codes), "\"". |
952 | | |
953 | | % already escaped |
954 | | type_symbol(Cs) --> typed_couple_inner(Cs). |
955 | | type_symbol(A) --> non_empty_symbol(Global), {Global == "global"}, "('", !, |
956 | | non_empty_symbol(GlobalType), ")", {append([Global,[40,39],GlobalType,[41]], A)}. |
957 | | % the global type has to be escaped for global(_) since it can be capitalised which results in a variable in Prolog |
958 | | type_symbol(A) --> non_empty_symbol(Global), {Global == "global"}, !, |
959 | | "(", non_empty_symbol(GlobalType), ")", {append([Global,[40,39],GlobalType,[39,41]], A)}. |
960 | ? | type_symbol(A) --> non_empty_symbol(A1), type_symbol_term(A2,0), !, {append(A1, A2, A)}. |
961 | | type_symbol(_,In,_) :- linecount(Line), |
962 | | format("lisp-style parser failed on line ~w expecting type_symbol on: ~s~n",[Line, In]),fail. |
963 | | |
964 | ? | type_symbol_term([40|A],Lvl) --> "(", {L1 is Lvl+1}, type_symbol_term(A,L1). |
965 | ? | type_symbol_term([41|A],Lvl) --> ")", {Lvl>0, L1 is Lvl-1}, type_symbol_term(A,L1). |
966 | ? | type_symbol_term(A,Lvl) --> non_empty_symbol(A1), type_symbol_term(A2,Lvl), {append(A1, A2, A)}. |
967 | ? | type_symbol_term(A,Lvl) --> typed_couple_inner(A1), !, type_symbol_term(A2,Lvl), {append(A1, A2, A)}. |
968 | | type_symbol_term(A,0) --> non_empty_symbol(A). |
969 | | type_symbol_term([],0) --> "". |
970 | | |
971 | | non_empty_symbol([A|As]) --> |
972 | | [A], |
973 | | { 65 =< A, A =< 90 |
974 | | ; 97 =< A, A =< 122 |
975 | | % ; 48 =< A, A =< 57 |
976 | | ; 913 =< A, A =< 937 % upper-case greek letters |
977 | | ; 945 =< A, A =< 969 % lower-case greek letters |
978 | | ; A = 124 % "|" |
979 | | ; A = 95 % "_", |
980 | | ; A = 45 % "-" |
981 | | ; A = 39 % "'" |
982 | | ; A = 33 % "!" |
983 | | ; 60 =< A, A =< 62 % "<", "=", ">" |
984 | | },!, |
985 | | symbol(As). |
986 | | |
987 | | symbol([A|As]) --> |
988 | | [A], |
989 | | { 65 =< A, A =< 90 |
990 | | ; 97 =< A, A =< 122 |
991 | | ; 48 =< A, A =< 57 |
992 | | ; 913 =< A, A =< 937 % upper-case greek letters |
993 | | ; 945 =< A, A =< 969 % lower-case greek letters |
994 | | ; A = 124 % "|" |
995 | | ; A = 95 % "_", |
996 | | ; A = 45 % "-" |
997 | | ; A = 39 % "'" |
998 | | ; A = 33 % "!" |
999 | | ; 60 =< A, A =< 62 % "<", "=", ">" |
1000 | | ; A = 8242 % Unicode Prime, should we also allow this as first symbol? |
1001 | | },!, |
1002 | | symbol(As). |
1003 | | symbol([]) --> "". |
1004 | | |
1005 | | string_symbol([34|As]) --> |
1006 | | % Z3 escapes double quotes with double quotes while ProB uses \" |
1007 | | [34,34], |
1008 | ? | string_symbol(As). |
1009 | | string_symbol([A|As]) --> |
1010 | | [A], |
1011 | | { 35 =< A, A =< 126 |
1012 | | ; A = 33 % "!" |
1013 | | }, |
1014 | ? | string_symbol(As). |
1015 | | string_symbol([]) --> "". |