1 % (c) 2015-2019 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
7 :- use_module(probsrc(module_information),[module_info/2]).
8 :- module_info(group,smt_solvers).
9 :- module_info(description,'This module translates the models found by an SMT-solvers to a ProB state.').
10
11 :- use_module(library(lists), [maplist/3,maplist/4,
12 %convlist/3,delete/3,
13 is_list/1]).
14 :- use_module(library(avl)).
15
16 :- use_module(probsrc(translate), [translate_bvalue/2]).
17 :- use_module(probsrc(tools), [arg_is_number/2,
18 split_atom/3,
19 ajoin/2]).
20 :- use_module(probsrc(tools_strings), [convert_to_number/2]).
21 :- use_module(probsrc(error_manager), [add_error_fail/3]).
22 :- use_module(probsrc(bsyntaxtree), [safe_create_texpr/3,
23 unique_typed_id/3,
24 %conjunct_predicates/2,
25 get_texpr_type/2,
26 get_texpr_id/2,
27 %create_implication/3,
28 %create_negation/2,
29 replace_id_by_expr/4]).
30 :- use_module(probsrc(custom_explicit_sets), [try_expand_custom_set_to_list/4]).
31 :- use_module(probsrc(b_global_sets), [b_type2_set/2]).
32
33 %:- use_module(probsrc(self_check), [assert_must_succeed/1]).
34
35 :- use_module(solver_dispatcher).
36
37 translate_smt_model_to_b_values(Solver,State,Identifiers,Bindings) :-
38 maplist(translate_smt_model_to_b_value(Solver,State),Identifiers,Bindings).
39
40 translate_smt_model_to_b_value(Solver,State,b(identifier(Id),Type,_Infos),binding(Id,Value,PPValue)) :-
41 member(id(Id,Expr),State),
42 smt_solver_interface_call(Solver,get_string(Expr,String)), !,
43 atom_codes(String,Codes),
44 % format('Result of get_string: ~s~n',[Codes]),
45 % trace,
46 lisp_style_expression(E,Codes,[]), !,
47 (Solver == cvc4 -> translate_cvc4_tree(E,Type,Value) ;
48 Solver == z3 -> translate_z3_tree(Id,E,Type,Value) ;
49 otherwise -> fail),
50
51 (translate_bvalue(Value,PPValue) -> true ; PPValue='**pretty-print failed**').
52
53 translate_z3_tree(Id,Id,Type,Result) :- !,
54 % variable is not assigned (hence z3 returns its name)
55 % just ground it somehow
56 z3_ground_result(Type,Result).
57 translate_z3_tree(Id,EscapedId,Type,Result) :-
58 % the id might have been escaped in z3 (e.g. due to ticks)
59 ajoin(['|',Id,'|'],EscapedId), !,
60 % variable is not assigned (hence z3 returns its name)
61 % just ground it somehow
62 z3_ground_result(Type,Result).
63 translate_z3_tree(_,E,Type,Result) :-
64 translate_z3_tree(E,Type,Result).
65 translate_z3_tree(['-',Number],integer,int(X)) :- !,
66 X is -Number.
67 translate_z3_tree(Number,integer,int(Number)).
68 translate_z3_tree(Number,global(Set),fd(ResNumber,Set)) :-
69 integer(Number), !,
70 ResNumber is Number + 1.
71 translate_z3_tree(Number,global(Set),fd(ResNumber,Set)) :-
72 split_atom(Number,['!'],[Set,val,InternalNumber]),
73 convert_to_number(InternalNumber,Nr),
74 ResNumber is Nr + 1.
75 translate_z3_tree(A,boolean,Res) :-
76 (A == true -> Res = pred_true ;
77 A == false -> Res = pred_false ;
78 otherwise -> fail).
79 translate_z3_tree([couple,A,B],couple(X,Y),(AT,BT)) :-
80 translate_z3_tree(A,X,AT),
81 translate_z3_tree(B,Y,BT).
82 translate_z3_tree(['_','as-array',AuxFunName],set(X),Res) :-
83 % set is represented by aux function
84 % get and parse the full model
85 smt_solver_interface_call(z3,get_full_model_string(FullModel)),
86 % format('z3 full model:~n~w~n',[FullModel]),
87 z3_model_to_avl(FullModel,AVL), !,
88 z3_set_to_b_set(AuxFunName,X,AVL,Res).
89 translate_z3_tree([store,Sub,Entry,true],set(X),ListOut) :-
90 translate_z3_tree(Sub,set(X),SubEntries),
91 translate_z3_tree(Entry,X,BEntry),
92 sort([BEntry|SubEntries],ListOut).
93 translate_z3_tree([[as,const,['Array',_,'Bool']],false],set(_),[]).
94 translate_z3_tree([[as,const,['Array',_,'Bool']],true],set(Type),Res) :-
95 b_type2_set(Type,Res).
96 translate_z3_tree(['record'|Z3Fields],record(Fields),rec(FieldsOut)) :-
97 maplist(translate_z3_record,Fields,Z3Fields,FieldsOut).
98 translate_z3_tree([let,[[Id,Val]],Function],Type,Out) :-
99 z3_replace_let_id_by_value(Id,Val,Function,NewFunction),
100 translate_z3_tree(NewFunction,Type,Out).
101
102 translate_z3_record(field(Name,BType),CVCVal,field(Name,BVal)) :-
103 translate_z3_tree(CVCVal,BType,BVal).
104
105 z3_ground_result(integer,int(0)).
106 z3_ground_result(boolean,pred_true).
107 z3_ground_result(couple(X,Y),(XG,YG)) :-
108 z3_ground_result(X,XG), z3_ground_result(Y,YG).
109 z3_ground_result(set(_),[]).
110 z3_ground_result(record(Fields),rec(FieldsOut)) :-
111 maplist(z3_ground_record_fields,Fields,FieldsOut).
112
113 z3_ground_record_fields(field(Name,BType),field(Name,BVal)) :-
114 z3_ground_result(BType,BVal).
115
116 :- use_module(probsrc(b_interpreter),[b_compute_expression_nowf/4]).
117 z3_set_to_b_set(FunName,ResType,AVL,ResultOut) :-
118 avl_fetch(FunName,AVL,f([[ParamName,_ParamType]],_ReturnType,Tree)),
119
120 safe_create_texpr(identifier(ParamName),ResType,IdA),
121 unique_typed_id("tmp",boolean,IdB),
122 z3_function_to_b_pred(Tree,Pred,IdA,IdB,AVL),
123 unique_typed_id("tmp",boolean,IDPredType),
124 safe_create_texpr(equal(IDPredType,Pred),pred,IsEqual),
125 safe_create_texpr(comprehension_set([IdA,IDPredType],IsEqual),set(couple(ResType,boolean)),TheFunction),
126
127 safe_create_texpr(function(TheFunction,IdA),boolean,FCall),
128 safe_create_texpr(equal(b(boolean_true,boolean,[]),FCall),pred,NewNewPred),
129 safe_create_texpr(comprehension_set([IdA],NewNewPred),set(ResType),CompSet),
130 % translate:set_unicode_mode,translate:print_bexpr(CompSet),
131 b_compute_expression_nowf(CompSet,[],[],Res),
132 (try_expand_custom_set_to_list(Res,ResultOut,true,z3_set_to_b_set)
133 -> true
134 ; ResultOut = Res).
135 z3_set_to_b_set(A,B,_,_) :-
136 add_error_fail(model_translation, 'z3_set_to_b_set failed on fun / result pair', [A,B]).
137
138 %z3_type_to_b_type('Int',integer).
139 %z3_type_to_b_type('Bool',boolean).
140
141 z3_function_to_b_pred([ite,[Op,_ParamName,Val],Result|Ifs],Pred,IdParam,IdReturn,AVL) :- !,
142 z3_function_to_b_pred(Ifs,SubPred,IdParam,IdReturn,AVL),
143 get_texpr_type(IdReturn,ReturnType), get_texpr_type(IdParam,ParamType),
144
145 %translate_z3_tree(Result,ReturnType,Value),
146 %safe_create_texpr(equal(IdReturn,b(value(Value),ReturnType,[])),pred,Then),
147 z3_function_to_b_pred(Result,Then,IdParam,IdReturn,AVL),
148
149 translate_z3_tree(Val,ParamType,Value2),
150 (Op = '=' -> safe_create_texpr(equal(IdParam,b(value(Value2),ParamType,[])),pred,If) ;
151 Op = '<=' -> safe_create_texpr(less_equal(IdParam,b(value(Value2),ParamType,[])),pred,If) ;
152 Op = '>=' -> safe_create_texpr(greater_equal(IdParam,b(value(Value2),ParamType,[])),pred,If) ;
153 otherwise -> fail),
154
155 safe_create_texpr(if_then_else(If,Then,SubPred),ReturnType,Pred).
156 z3_function_to_b_pred([let,[[Id,Val]],Function],Pred,IdParam,IdReturn,AVL) :- !,
157 z3_replace_let_id_by_value(Id,Val,Function,NewFunction),
158 z3_function_to_b_pred(NewFunction,Pred,IdParam,IdReturn,AVL).
159 % unwraps lower levels
160 z3_function_to_b_pred([X],Pred,IdParam,IdReturn,AVL) :- !,
161 z3_function_to_b_pred(X,Pred,IdParam,IdReturn,AVL).
162 % function composition
163 z3_function_to_b_pred([X,ParamName],Pred,IdParam,IdReturn,AVL) :- % TODO Id return
164 get_texpr_id(IdParam,ParamName), !,
165 avl_fetch(X,AVL,f([[ParamName,_ParamType]],_ReturnType,XBody)),
166 z3_function_to_b_pred(XBody,Pred,IdParam,IdReturn,AVL).
167 z3_function_to_b_pred(['-',Int],Pred,_IdParam,_IdReturn,_AVL) :- !,
168 translate_z3_tree(Int,integer,int(Value)),
169 MValue is -Value,
170 Pred = b(value(int(MValue)),integer,[]).
171 z3_function_to_b_pred([X|Further],Pred,IdParam,IdReturn,AVL) :- !,
172 get_texpr_type(IdParam,SubParamType),
173 unique_typed_id("tmp",SubParamType,IdB),
174 z3_function_to_b_pred(Further,FurtherPred,IdParam,IdB,AVL),
175
176 avl_fetch(X,AVL,f([[_XParamName,_ParamType]],_ReturnType,XBody)),
177 z3_function_to_b_pred(XBody,XPred,IdB,IdReturn,AVL),
178
179 get_texpr_id(IdB,IdToReplace),
180 replace_id_by_expr(XPred,IdToReplace,FurtherPred,Pred).
181 z3_function_to_b_pred(SingleVal,Pred,_,IdReturn,_) :-
182 get_texpr_type(IdReturn,ReturnType),
183 translate_z3_tree(SingleVal,ReturnType,Value),
184 Pred = b(value(Value),ReturnType,[]).
185
186 z3_replace_let_id_by_value(Id,Val,Function,NewFunction) :-
187 is_list(Function), !,
188 maplist(z3_replace_let_id_by_value(Id,Val),Function,NewFunction).
189 z3_replace_let_id_by_value(Id,Val,Function,NewFunction) :-
190 atomic(Function), !,
191 Id = Function -> NewFunction = Val ; NewFunction = Function.
192
193 z3_model_to_avl(FullModel,AVL) :-
194 atom_codes(FullModel,Codes),
195 lisp_style_expressions(E,Codes,[]),
196 z3_lisp_to_avl(E,AVL).
197
198 z3_lisp_to_avl(E,AVL) :-
199 empty_avl(In),
200 z3_lisp_to_avl(E,In,AVL).
201
202 z3_lisp_to_avl([],A,A).
203 z3_lisp_to_avl([['define-fun',Name,Param,Return,Tree]|T],AIn,AOut) :-
204 avl_store(Name,AIn,f(Param,Return,Tree),ATemp),
205 z3_lisp_to_avl(T,ATemp,AOut).
206 % currently I think I do not need these facts...
207 % as far as I understand they represent enumerated set Elements
208 z3_lisp_to_avl([['declare-fun',_Name,_Params,_Type0]|T],AIn,AOut) :-
209 z3_lisp_to_avl(T,AIn,AOut).
210 % these occur for cardinality constraints
211 z3_lisp_to_avl([['forall',_Vars,_Pred]|T],AIn,AOut) :-
212 z3_lisp_to_avl(T,AIn,AOut).
213
214 translate_cvc4_tree(['CONST_RATIONAL',Arg],integer,int(Val)) :-
215 arg_is_number(Arg,Val).
216 translate_cvc4_tree(['CONST_BOOLEAN',1],boolean,pred_true).
217 translate_cvc4_tree(['CONST_BOOLEAN',0],boolean,pred_false).
218 translate_cvc4_tree(['CONST_STRING',Content],string,string(Content)).
219 translate_cvc4_tree(['SINGLETON',ValIn],set(X),[ValOut]) :-
220 translate_cvc4_tree(ValIn,X,ValOut).
221 translate_cvc4_tree(['EMPTYSET',emptyset,_Type],set(_),[]).
222 translate_cvc4_tree(['TUPLE',V1,V2],couple(Type1,Type2),(TV1,TV2)) :-
223 translate_cvc4_tree(V1,Type1,TV1),
224 translate_cvc4_tree(V2,Type2,TV2).
225 translate_cvc4_tree(['APPLY_CONSTRUCTOR','__cvc4_tuple_ctor',V1,V2],couple(Type1,Type2),(TV1,TV2)) :-
226 translate_cvc4_tree(V1,Type1,TV1),
227 translate_cvc4_tree(V2,Type2,TV2).
228 translate_cvc4_tree(['UNION',V1,V2],set(X),Val) :-
229 translate_cvc4_tree(V1,set(X),TV1),
230 translate_cvc4_tree(V2,set(X),TV2),
231 append(TV1,TV2,Val).
232 translate_cvc4_tree(['UNINTERPRETED_CONSTANT',C],global(SId),fd(PBCId,SId)) :-
233 atom_codes(C,CCodes),
234 parse_uc(CId,CCodes,[]),
235 PBCId is CId + 1.
236 translate_cvc4_tree(['RECORD',_CVCRecordType|Fields],record(RFields),rec(FieldsOut)) :-
237 maplist(translate_cvc4_record,RFields,Fields,FieldsOut).
238
239 translate_cvc4_record(field(Name,BType),CVCVal,field(Name,BVal)) :-
240 translate_cvc4_tree(CVCVal,BType,BVal).
241
242 parse_uc(Id) -->
243 "uc__SORT_TYPE_var_", number(_),
244 "__", number(N), {number_codes(Id,N)}.
245
246 lisp_style_expressions([E|Es]) -->
247 ws, lisp_style_expression(E), ws, !,
248 lisp_style_expressions(Es).
249 lisp_style_expressions([]) --> ws, [].
250 lisp_style_expressions(_,In,_) :-
251 format("lisp-style parser failed on: ~s~n",[In]),fail.
252
253 ws --> [W], {W = 32 ; W = 10 ; W = 13}, ws.
254 ws --> ";;", any_but_newline.
255 ws --> [].
256 any_but_newline --> [C], {C \= 10}, any_but_newline ; "\n", ws.
257
258 lisp_style_expression(A) --> non_empty_symbol(Cs), {atom_codes(A, Cs)}.
259 lisp_style_expression(N) --> number(Cs), {number_codes(N, Cs)}.
260 lisp_style_expression(N) --> "-", number(Cs), {number_codes(N2,Cs), N is -N2}.
261 lisp_style_expression(A) --> string(Codes), {atom_codes(A,Codes)}.
262 lisp_style_expression(List) --> "(", lisp_style_expressions(List), ")".
263 lisp_style_expression(record_type(Fields)) -->
264 "[#", ws, record_type_fields(Fields), ws, "#]".
265
266 record_type_fields([F|Fields]) -->
267 record_type_field(F), ws, ",", ws, record_type_fields(Fields).
268 record_type_fields([F]) --> record_type_field(F).
269
270 record_type_field(field(NameA,TypeA)) -->
271 non_empty_symbol(Name), ":(TYPE_CONSTANT ", non_empty_symbol(Type), " type)",
272 {atom_codes(NameA,Name),atom_codes(TypeA,Type)}.
273
274 number([D|Ds]) --> digit(D), number(Ds).
275 number([D]) --> digit(D).
276
277 digit(D) --> [D], {48 =< D, D =< 57}.
278
279 string(Codes) --> "\"", non_empty_symbol(Codes), "\"".
280
281 non_empty_symbol([A|As]) -->
282 [A],
283 { 65 =< A, A =< 90
284 ; 97 =< A, A =< 122
285 % ; 48 =< A, A =< 57
286 ; A = 124 % "|"
287 ; A = 95 % "_"
288 ; A = 45 % "-"
289 ; A = 39 % "'"
290 ; A = 33 % "!"
291 ; 60 =< A, A =< 62 % "<", "=", ">"
292 },
293 symbol(As).
294
295 symbol([A|As]) -->
296 [A],
297 { 65 =< A, A =< 90
298 ; 97 =< A, A =< 122
299 ; 48 =< A, A =< 57
300 ; A = 124 % "|"
301 ; A = 95 % "_"
302 ; A = 45 % "-"
303 ; A = 39 % "'"
304 ; A = 33 % "!"
305 ; 60 =< A, A =< 62 % "<", "=", ">"
306 },
307 symbol(As).
308 symbol([]) --> "".