translate_z3_expr(['-',Number],_,integer,Res) :-
!,
Number1 is -Number,
Res=b(integer(Number1),integer,[]).
translate_z3_expr(Int,_,integer,Res) :- integer(Int),!, Res=b(integer(Int),integer,[]).
translate_z3_expr(true,_,boolean,Res) :- !, Res=b(boolean_true,boolean,[]).
translate_z3_expr(false,_,boolean,Res) :- !, Res=b(boolean_false,boolean,[]).
translate_z3_expr([ZOP|T], Env, boolean, Res) :-
z3_connective_to_b(ZOP, BOP),
!,
translate_z3_connective(BOP, T, Env, PredRes),
Res = b(convert_bool(PredRes),boolean,[]).
translate_z3_expr(['-',RealAtom], Env, real, Res) :-
atom(RealAtom),
atom_concat('-', RealAtom, NRealAtom),
translate_z3_expr(NRealAtom, Env, real, Res).
translate_z3_expr(Atom, _, Type, Res) :-
atom(Atom),
virtual_deferred_set_id(Atom, FdVar),
FdVar = fd(_,DefSet),
Type = global(DefSet),
!,
Res = b(value(FdVar),Type,[]).
translate_z3_expr(Atom, _, Type, Res) :-
atom(Atom),
( ( split_atom(Atom,['!'],Splitted),
Splitted = [Set,val,InternalNumber]
)
-> Type = global(Set),
!,
convert_to_number(InternalNumber,Nr),
ResNumber is Nr + 1,
Val = fd(ResNumber,Set),
asserta(fd_var_of_z3(Set,ResNumber)),
( global_type(Val,Set)
-> true
; handle_globalsets_fdrange_contradiction(ResNumber,Set)
),
safe_create_texpr(value(Val), global(Set), Res)
; % atom could represent a real number
Type = real,
atom_to_number(Atom, Real),
float(Real), !,
safe_create_texpr(real(Atom), real, Res)
).
translate_z3_expr(Nr,_,global(GS),Res) :- number(Nr),!, % Z3 represents first element of GS by 0, ...
Nr1 is Nr+1, Val = fd(Nr1,GS),
asserta(fd_var_of_z3(GS,Nr1)),
( global_type(Val,GS)
-> true
; handle_globalsets_fdrange_contradiction(Nr1,GS)
),
safe_create_texpr(value(Val), global(GS), Res).
translate_z3_expr([Couple,A,B],Env,couple(T1,T2),b(couple(AT,BT),couple(T1,T2),[])) :-
atom(Couple),
get_couple_type_from_atom(Couple, T1, T2),
translate_z3_expr(A, Env, T1, AT),
translate_z3_expr(B, Env, T2, BT).
translate_z3_expr([CouplePrj,Arg], Env, Type, Res) :-
atom(CouplePrj),
translate_z3_expr(Arg, Env, _, RArg),
get_texpr_type(RArg, CType),
( atom_prefix('get_x_couple', CouplePrj),
PrjNode = first_of_pair(RArg),
CType = couple(ResType,_)
; atom_prefix('get_y_couple', CouplePrj),
PrjNode = second_of_pair(RArg),
CType = couple(_,ResType)
),
!,
Type = ResType,
safe_create_texpr(PrjNode, ResType, Res).
translate_z3_expr(Id, env(Env,_AVL), Type, Res) :-
atom(Id),
TId = b(identifier(Id),Type,_),
member(TId, Env),
!,
Res = TId.
translate_z3_expr(Id, _, Type, Res) :-
atom(Id),
Type = global(_),
% global ids which are not in the environment
!,
safe_create_texpr(identifier(Id), Type, Res).
translate_z3_expr(CstFunc,env(Env,AVL),Type,CompSet) :- atom(CstFunc),
Type = set(couple(PType,RType)),
avl_fetch(CstFunc,AVL,'z3-define-fun'([[ParamName,ParameterType]],ReturnType,BodyTree)),
z3_type_to_b_type(ParameterType,PType), % check if type matches
z3_type_to_b_type(ReturnType,RType), % ditto
!,
PID = b(identifier(ParamName),PType,[]),
%print(translate_body(CstFunc,PID)),nl,
translate_z3_expr(BodyTree,env([PID|Env],AVL),RType,BodyExpr),
%print(body(CstFunc)),translate:print_bexpr(BodyExpr),nl,
unique_typed_id("lambda",RType,LambdaID),
create_equality(LambdaID,BodyExpr,CPred),
% {PID,lambda | lambda = BodyExpr}
safe_create_texpr(comprehension_set([PID,LambdaID],CPred), set(couple(PType,RType)), CompSet).
translate_z3_expr([CstFunc,Arg],env(Env,AVL),Type,Res) :- % function application
avl_fetch(CstFunc,AVL,'z3-define-fun'([[ParamID,ParameterType]],ReturnType,BodyTree)),
z3_type_to_b_type(ReturnType,Type), % check if type matches
!,
( ParamID == Arg % special case if argument and parameter identical
-> translate_z3_expr(BodyTree,env(Env,AVL),Type,Res)
; z3_type_to_b_type(ParameterType,PType), % TO DO: couple-> ground type; PType could be not ground !
translate_z3_expr(CstFunc,env(Env,AVL),set(couple(PType,Type)),TFun),
translate_z3_expr(Arg,env(Env,AVL),PType,TArg),
create_texpr(function(TFun,TArg),Type,[contains_wd_condition],Res)
).
translate_z3_expr([let,[[Id,Val]],Function],Env,Type,Res) :- !,
z3_replace_let_id_by_value(Id,Val,Function,NewFunction),
translate_z3_expr(NewFunction,Env,Type,Res).
translate_z3_expr([let,[[Id,Val]|T],Function],Env,Type,Res) :-
T \== [],
z3_replace_let_id_by_value(Id,Val,Function,NewFunction),
translate_z3_expr([let,T,NewFunction],Env,Type,Res).
translate_z3_expr([ZOP, Left], Env, Type,Res) :-
z3_unary_expr_to_b(ZOP, BOP, Type),!,
translate_z3_expr(Left, Env, Type, TL),
Expr =.. [BOP,TL],
safe_create_texpr(Expr, Type, Res).
translate_z3_expr([ZOP|Args], Env, Type, Res) :-
% operators such as multiplication can have an arbitrary arity like [*,x,x,x]
z3_binary_expr_to_b(ZOP, BOP, TA, TB, Type), !,
create_nested_binary_expr(BOP, Env, Type, TA, TB, Args, Res).
translate_z3_expr([ite, Test, Left, Right], Env, Type, Res) :- !,
translate_z3_predicate(Test,Env, BTest),
translate_z3_expr(Left, Env, Type, BThen),
translate_z3_expr(Right,Env, Type, BElse), get_texpr_type(BThen,Type),
safe_create_texpr(if_then_else(BTest,BThen,BElse),Type,Res).
translate_z3_expr(String,_,string,Res) :-
atom(String),
!,
Res = b(string(String),string,[]).
translate_z3_expr(['_','as-array',AuxFunName],_,set(X),Res) :- !,
% set is represented by aux function
translate_z3_expr_using_full_model(AuxFunName,set(couple(X,boolean)),ChFunSet),
% we computed the characteristic function of the set; now convert it to a set
% Now we need to compute dom(ChFunSet |> {TRUE}) = ChFunSet~[{TRUE}] = {x|ChFunSet(x)=TRUE}
unique_typed_id("el!",X,Element),
create_texpr(function(ChFunSet,Element),boolean,[contains_wd_condition],FCall),
create_equality(b(boolean_true,boolean,[]),FCall,NewNewPred),
safe_create_texpr(comprehension_set([Element],NewNewPred),set(X),CompSet),
% translate:print_bexpr(CompSet),nl,
compute_bcomp_set(CompSet,Set),
Res = b(value(Set),set(X),[]).
translate_z3_expr([store,Sub,Entry,TStoreRes],Env,set(Type),Res) :-
% TStoreRes can be true, false or a predicate which needs to be evaluated first
translate_z3_expr(Sub,Env,set(Type),S1),
translate_z3_expr(Entry,Env,Type,El2),
S2 = b(set_extension([El2]),set(Type),[]),
( (TStoreRes = true; TStoreRes = false)
-> StoreRes = TStoreRes
; translate_z3_predicate(TStoreRes, Env, BStoreRes),
( b_test_boolean_expression_cs(BStoreRes, [], [],'translating Z3 value',0)
-> StoreRes = true
; StoreRes = false
)
),
( StoreRes = true
-> Expr = union(S1,S2)
; StoreRes = false,
Expr = set_subtraction(S1,S2)
),
!,
b_compute_expression_nowf(b(Expr,set(Type),[]), [], [], List,'translating Z3 value',0),
Res = b(value(List),set(Type),[]).
translate_z3_expr([[as,const,['Array',Z3Type,'Bool']],false],_,Type,b(value([]),Type,[])) :-
( (Type = set(BType), z3_type_to_b_type(Z3Type,BType))
-> true
; add_error(translate_z3_expr,'Unexpected type in Z3 model: ',types(Z3Type,Type))
),
!.
translate_z3_expr([[as,const,['Array',Z3Type,'Bool']],true],_,Type,b(value(Res),Type,[])) :-
( (Type = set(BType), z3_type_to_b_type(Z3Type,BType))
-> b_type2_set(BType,Res),
!
; add_error(translate_z3_expr,'Unexpected type in Z3 model: ',types(Z3Type,Type)),
fail
).
translate_z3_expr(['record'|Z3Fields],Env,record(Fields),b(rec(FieldsOut),record(Fields),[])) :-
maplist(translate_z3_record(Env),Fields,Z3Fields,FieldsOut).
translate_z3_expr([iteration,Rel,Int],Env,set(CoupleType),Res) :-
translate_z3_expr(Rel,Env,set(CoupleType),TRel),
translate_z3_expr(Int,Env,integer,BInt),
Iteration = b(iteration(TRel,BInt),set(CoupleType),[]),
( BInt = b(integer(_),_,_)
-> compute_bcomp_set(Iteration,Set),
Res = b(value(Set),set(CoupleType),[])
; Res = Iteration
).
translate_z3_expr([lambda,[[ClosureVar,ClosureVarType]],Body],Env,SetType,Res) :-
( ClosureVar = refl_closure_g_u_var
-> Functor = reflexive_closure
; ClosureVar = closure_g_u_var,
Functor = closure
),
!,
z3_type_to_b_type(ClosureVarType,BType),
TClosureVar = b(identifier(ClosureVar),BType,[]),
% compute closure with ProB if Z3 does not unfold lambda,
% the translated model itself (lambda(exists(...))) is too complex so we catch translated closures here
Env = env(Ids,B),
translate_z3_predicate(Body, env([TClosureVar|Ids],B), TBody),
TBody = b(exists(_,ExistsBody),pred,_),
conjunction_to_list(ExistsBody, ExistsBodyConj),
member(b(exists(_,ExistsBody2),pred,_), ExistsBodyConj),
conjunction_to_list(ExistsBody2, ExistsBodyConj2),
member(b(equal(b(identifier(_),SetType,_),b(iteration(TRel,_),SetType,_)),pred,[]), ExistsBodyConj2),
!,
BNode =.. [Functor,TRel],
TRes = b(BNode,SetType,[]),
clean_up(TRes, [], Res).
translate_z3_expr([lambda,Args,Body],env(Ids,_),set(BType),Res) :-
% see for instance ':z3-double-check f = %x.(x : INTEGER|x * x * x) & f(f(x)) = y & y = 512'
Args = [[ID,Z3Type]],
z3_type_to_b_type(Z3Type,BType),
TID = b(identifier(ID),BType,[]),
Body = [exists|_],
translate_z3_predicate(Body,env([TID|Ids],empty),TBody),
TBody = b(exists([LambdaID],ExistsBody),pred,_),
conjunction_to_list(ExistsBody, ExistsList),
select(ExistsBody, ExistsList, RestExistsList),
ExistsBody = b(equal(CoupleCst,ExistCouple),pred,_),
CoupleCst = b(identifier('_couple_cst'),couple(_,_),_),
conjunct_predicates(RestExistsList, RestExistsBody),
!,
ExistCouple = b(couple(_,ExistsExpr),_,_),
safe_create_texpr(lambda([LambdaID],RestExistsBody,ExistsExpr), set(BType), BLambda),
clean_up(BLambda, [], CompSet),
compute_bcomp_set(CompSet,Set),
Res = b(value(Set),set(BType),[]).
translate_z3_expr([lambda,Args,Body],env(Ids,B),set(BType),Res) :-
Args = [[ID,Z3Type]], % TO DO: more than one argument?
z3_type_to_b_type(Z3Type,BType),
!,
TID = b(identifier(ID),BType,[]),
translate_z3_predicate(Body,env([TID|Ids],B),TBody),
safe_create_texpr(comprehension_set([TID],TBody),set(BType),CompSet),
%print('lambda: '),translate:print_bexpr(CompSet),nl, print(CompSet),nl,
compute_bcomp_set(CompSet,Set),
Res = b(value(Set),set(BType),[]).
translate_z3_expr([['_',map,AndOrTerm]|T], Env, _, Res) :-
( AndOrTerm = [AndOr,['Bool','Bool'],'Bool'] % prior version 4.12.2
; AndOrTerm = AndOr % since version 4.12.2
),
( AndOr == and
; AndOr == or
),
!,
map_translate_z3_expr(T, Env, [], TT),
TT = [b(_,SetType,_)|_],
( AndOr == and
-> unfold_general_intersection(TT, SetType, Res)
; unfold_general_union(TT, SetType, Res)
).
translate_z3_expr([mod,A,B], Env, integer, Res) :-
!,
translate_z3_expr(A, Env, integer, BA),
translate_z3_expr(B, Env, integer, BB),
BIsZero = b(equal(BB,b(integer(0),integer,[])),pred,[]),
% return 0 if B is zero, otherwise (= (mod x y) (- x (* y (div x y)))) holds
ModEq = b(minus(BA,b(multiplication(BB,
b(floored_div(BA,BB),integer,[contains_wd_condition])),integer,[contains_wd_condition])),
integer,[contains_wd_condition]),
safe_create_texpr(if_then_else(BIsZero,b(integer(0),integer,[]),ModEq),integer,TRes),
clean_up(TRes, [], Res).
translate_z3_expr([rem,A,B], Env, integer, Res) :-
!,
translate_z3_expr(A, Env, integer, BA),
translate_z3_expr(B, Env, integer, BB),
BIsZero = b(equal(BB,b(integer(0),integer,[])),pred,[]),
BLowerZero = b(less(BB,b(integer(0),integer,[])),pred,[]),
% 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
ModEq = b(minus(BA,b(multiplication(BB,
b(floored_div(BA,BB),integer,[contains_wd_condition])),integer,[contains_wd_condition])),
integer,[contains_wd_condition]),
safe_create_texpr(if_then_else(BLowerZero,b(unary_minus(ModEq),integer,[]),ModEq),integer,IfExpr),
safe_create_texpr(if_then_else(BIsZero,b(integer(0),integer,[]),IfExpr),integer,TRes),
clean_up(TRes, [], Res).
translate_z3_expr(Expr,_,Type,_) :-
\+ check_error_occured(translate_z3_expr_globalsets_fdrange, _),
add_error_fail(translate_z3_expr, 'Missing translation for Z3 expression:', Expr:Type).