1 | % (c) 2009-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(kodkod_translate, | |
6 | [ kodkod_translate/4 | |
7 | , remove_optional_set/2 | |
8 | ]). | |
9 | ||
10 | :- use_module(library(lists)). | |
11 | :- use_module(library(avl)). | |
12 | :- use_module(library(ordsets)). | |
13 | ||
14 | :- use_module(probsrc(module_information),[module_info/2]). | |
15 | :- use_module(probsrc(bsyntaxtree)). | |
16 | :- use_module(probsrc(bmachine)). | |
17 | :- use_module(probsrc(translate), [pretty_type/2,translate_bexpression/2]). | |
18 | :- use_module(probsrc(custom_explicit_sets),[expand_custom_set_to_list/2]). | |
19 | :- use_module(probsrc(tools),[foldl/4]). | |
20 | ||
21 | :- use_module(kodkod_tools). | |
22 | ||
23 | :- module_info(group,kodkod). | |
24 | :- module_info(description,'This module contains the code to translate B expressions and predicates into Kodkod.'). | |
25 | ||
26 | kodkod_translate(TExpr,Typemap,Idmap,KExpr) :- | |
27 | create_environment(Typemap,Idmap,KEnv), | |
28 | kodkod_translate1(TExpr,KEnv,KExpr). | |
29 | ||
30 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
31 | % the translation environment: It stores | |
32 | % 1) the types (and represented by which relation), | |
33 | % 2) the identifiers (and represented by which relation), | |
34 | % 3) the quantified variables (and their relation) | |
35 | create_environment(Typemap,Idmap,kenv(Typemap,Idmap,Varmap)) :- | |
36 | empty_avl(Varmap). | |
37 | lookup_type_relation(Type,kenv(Typemap,_,_),Relname) :- | |
38 | avl_fetch(Type,Typemap,V), | |
39 | V = relation(Relname,_Size,_Relspec). | |
40 | lookup_id_relation(Id,kenv(_,Idmap,_),Relname,Types) :- | |
41 | avl_fetch(Id,Idmap,reldef(Relname,Types,_,_,_)). | |
42 | lookup_var(Id,kenv(_,_,Varmap),Varname) :- | |
43 | avl_fetch(Id,Varmap,Varname). | |
44 | add_var_to_environment(Id,Ref,kenv(Typemap,Idmap,VarmapIn),kenv(Typemap,Idmap,VarmapOut)) :- | |
45 | avl_store(Id,VarmapIn,Ref,VarmapOut). | |
46 | ||
47 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
48 | % initialise the Kodkod environment | |
49 | ||
50 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
51 | % translate predicates and expressions | |
52 | kodkod_translate1(TExpr,Env,KExpr) :- | |
53 | get_texpr_expr(TExpr,Expr), | |
54 | get_texpr_type(TExpr,Type1), remove_seq_type(Type1,Type), | |
55 | get_texpr_info(TExpr,Info), | |
56 | kodkod_translate2(Expr,Type,Info,Env,KExpr1), | |
57 | % enforce the use of integer atoms for integers used in sets | |
58 | ( Type = set(integer), KExpr1 \= _:_ -> | |
59 | KExpr = KExpr1:rel([IntAtoms]), | |
60 | intset_relation_kodkod_name(IntAtoms) | |
61 | ; | |
62 | KExpr = KExpr1). | |
63 | ||
64 | remove_seq_type(seq(T),Set) :- !,Set=set(couple(integer,T)). | |
65 | remove_seq_type(T,T). | |
66 | ||
67 | :- use_module(probsrc(bsyntaxtree),[get_texpr_set_type/2]). | |
68 | :- use_module(probsrc(typing_tools),[create_maximal_type_set/2]). | |
69 | ||
70 | kodkod_translate2(member(BElem,BSet),pred,Info,Env,K) :- | |
71 | get_texpr_expr(BSet,BFun), | |
72 | BFun =.. [FunFunctor,BDom,BRange], | |
73 | KFun =.. [FunFunctor,KDom,KRange], | |
74 | get_texpr_type(BSet,Type), | |
75 | kodkod_translate_binary_membership(KFun,KElem,Type,Info,K),!, | |
76 | kodkod_translate1(BElem,Env,KElem), | |
77 | kodkod_translate1(BDom,Env,KDom), | |
78 | kodkod_translate1(BRange,Env,KRange). | |
79 | kodkod_translate2(not_member(BElem,BSet),pred,Info,Env,not(K)) :- | |
80 | !,kodkod_translate2(member(BElem,BSet),pred,Info,Env,K). | |
81 | kodkod_translate2(domain_restriction(Dom,Rel),set(couple(_,RhType)),_,Env, | |
82 | intersection(product(KDom,relref(KRhRel)),KRel)) :- | |
83 | !,kodkod_translate1(Dom,Env,KDom), | |
84 | kodkod_translate1(Rel,Env,KRel), | |
85 | lookup_type_relation(RhType,Env,KRhRel). | |
86 | kodkod_translate2(domain_subtraction(Dom,Rel),set(couple(_,RhType)),_,Env, | |
87 | intersection(product(difference(univ,KDom),relref(KRhRel)),KRel)) :- | |
88 | !,kodkod_translate1(Dom,Env,KDom), | |
89 | kodkod_translate1(Rel,Env,KRel), | |
90 | lookup_type_relation(RhType,Env,KRhRel). | |
91 | kodkod_translate2(range_restriction(Rel,Dom),set(couple(LhType,_)),_,Env, | |
92 | intersection(KRel,product(relref(KLhRel),KDom))) :- | |
93 | !,kodkod_translate1(Dom,Env,KDom), | |
94 | kodkod_translate1(Rel,Env,KRel), | |
95 | lookup_type_relation(LhType,Env,KLhRel). | |
96 | kodkod_translate2(range_subtraction(Rel,Dom),set(couple(LhType,_)),_,Env, | |
97 | intersection(KRel,product(relref(KLhRel),difference(univ,KDom)))) :- | |
98 | !,kodkod_translate1(Dom,Env,KDom), | |
99 | kodkod_translate1(Rel,Env,KRel), | |
100 | lookup_type_relation(LhType,Env,KLhRel). | |
101 | kodkod_translate2(identifier(Id),_BType,_Info,Env,Ref) :- !, | |
102 | ( lookup_var(Id,Env,Varname) -> | |
103 | Ref = varref(Varname) | |
104 | ; lookup_id_relation(Id,Env,Relname,_KTypes) -> | |
105 | Ref = relref(Relname) | |
106 | ; lookup_type_relation(global(Id),Env,Relname) -> | |
107 | Ref = relref(Relname)). | |
108 | kodkod_translate2(set_extension([]),BType,Info,Env,Result) :- | |
109 | !, % normally should not happen, unless AST constructed by hand | |
110 | kodkod_translate2(empty_set,BType,Info,Env,Result). | |
111 | kodkod_translate2(set_extension(List),_BType,_,Env,Result) :- | |
112 | !, kodkod_translate_l(List,Env,KList), | |
113 | kodkod_extension_set(KList,Result). | |
114 | kodkod_translate2(forall(BIds,_,_),pred,_,_Env,true) :- | |
115 | % If there is an identifier without possible solution, the result is always true | |
116 | somechk(is_inconsistent_expression,BIds),!. | |
117 | kodkod_translate2(forall(BIds, Condition, Predicate),pred,_,Env, | |
118 | forall(Decls,Result)) :- | |
119 | !,kodkod_declarations1(BIds,Env,Subenv,ProvDecls), | |
120 | kodkod_translate1(Condition,Subenv,KCond), | |
121 | kodkod_translate1(Predicate,Subenv,KPred), | |
122 | kodkod_declarations2(ProvDecls,Env,KCond,NewKCond,Decls), | |
123 | kodkod_implication(NewKCond,KPred,Result). | |
124 | kodkod_translate2(exists(BIds,_),pred,_,_Env,false) :- | |
125 | % If there is an identifier without possible solution, the result is always false | |
126 | somechk(is_inconsistent_expression,BIds),!. | |
127 | kodkod_translate2(exists([BId], Membership),pred,_,Env,some(KSet)) :- | |
128 | % translate #e.e:M to some(M) | |
129 | get_texpr_expr(Membership,member(Elem,Set)), | |
130 | get_texpr_id(BId,Id),get_texpr_id(Elem,Id),!, | |
131 | kodkod_translate1(Set,Env,KSet). | |
132 | kodkod_translate2(exists(BIds, Predicate),pred,_,Env,exists(Decls,Result)) :- | |
133 | !,kodkod_declarations1(BIds,Env,Subenv,ProvDecls), | |
134 | kodkod_translate1(Predicate,Subenv,KPred), | |
135 | kodkod_declarations2(ProvDecls,Env,KPred,Result,Decls). | |
136 | kodkod_translate2(comprehension_set(BIds,_),BType,Info,Env,KEmptySet) :- | |
137 | % If there is an identifier without possible solution, the result is always empty | |
138 | somechk(is_inconsistent_expression,BIds),!, | |
139 | kodkod_translate2(empty_set,BType,Info,Env,KEmptySet). | |
140 | kodkod_translate2(comprehension_set(BIds,Predicate),set(_BType),_,Env, | |
141 | comp(Decls,Result)) :- | |
142 | !,kodkod_declarations1(BIds,Env,Subenv,ProvDecls), | |
143 | kodkod_translate1(Predicate,Subenv,KPred), | |
144 | kodkod_declarations2(ProvDecls,Env,KPred,Result,Decls). | |
145 | kodkod_translate2(domain(Rel),_,_,Env,K) :- | |
146 | !,get_texpr_type(Rel,RelType), | |
147 | kodkod_domain(KRel,RelType,K), | |
148 | kodkod_translate1(Rel,Env,KRel). | |
149 | kodkod_translate2(range(Rel),_,_,Env,K) :- | |
150 | !,get_texpr_type(Rel,RelType), | |
151 | kodkod_range(KRel,RelType,K), | |
152 | kodkod_translate1(Rel,Env,KRel). | |
153 | kodkod_translate2(first_of_pair(Couple),Type,Info,Env,K) :- | |
154 | !,kodkod_translate2(domain(Couple),Type,Info,Env,K). | |
155 | kodkod_translate2(second_of_pair(Couple),Type,Info,Env,K) :- | |
156 | !,kodkod_translate2(range(Couple),Type,Info,Env,K). | |
157 | kodkod_translate2(composition(A,B),_BType,_,Env,join(KA,KB)) :- | |
158 | get_texpr_set_type(A,couple(_,IType)), | |
159 | type_arity(IType,1),!, | |
160 | kodkod_translate1(A,Env,KA), | |
161 | kodkod_translate1(B,Env,KB). | |
162 | kodkod_translate2(function(BFun,BArg),_BType,_,Env,Res) :- | |
163 | !, kodkod_function_application(BFun,BArg,Env,Res). | |
164 | kodkod_translate2(image(BRel,BArg),_BType,_,Env,Res) :- | |
165 | !, kodkod_function_application(BRel,BArg,Env,Res). | |
166 | kodkod_translate2(reverse(BRel),_BType,_,Env,Res) :- | |
167 | !, kodkod_reverse(BRel,Env,Res). | |
168 | kodkod_translate2(integer(I),integer,_,_Env,int(I)) :- !. | |
169 | kodkod_translate2(unary_minus(TExpr),integer,_,_Env,int(N)) :- | |
170 | % Expressions of the form "-(1)" are translated to "-1" | |
171 | % there is another rule below for other forms of unary minus (translating "-x" to "0-x") | |
172 | get_texpr_expr(TExpr,integer(P)),!,N is -P. | |
173 | kodkod_translate2(general_sum([TId],TPred,Expr),integer,_,Env,sum(KSet)) :- | |
174 | % we support only a restricted sort of the general sum: | |
175 | % SIGMA (x).(x:S|x) | |
176 | % The rewriting rules (see kodkod2.pl) convert the more general form "SIGMA (x).(P|x)" | |
177 | % into this form by "SIGMA (x).(x:{x|P}|x)" | |
178 | % The expression must only contain the quantified variable: | |
179 | get_texpr_id(TId,Id), get_texpr_id(Expr,Id),!, | |
180 | % Simple form: the predicate is of the form x:S | |
181 | get_texpr_expr(TPred,member(TElem,TSet)),get_texpr_id(TElem,Id), | |
182 | kodkod_translate1(TSet,Env,KSet). | |
183 | kodkod_translate2(boolean_true,boolean,_,Env,relref(Relname)) :- !, | |
184 | lookup_id_relation('__kodkod__true',Env,Relname,_KTypes). | |
185 | kodkod_translate2(boolean_false,boolean,_,Env,relref(Relname)) :- !, | |
186 | lookup_id_relation('__kodkod__false',Env,Relname,_KTypes). | |
187 | kodkod_translate2(bool_set,set(boolean),_,Env,relref(Relname)) :- !, | |
188 | lookup_type_relation(boolean,Env,Relname). | |
189 | kodkod_translate2(empty_set,set(T),_,Env,Empty) :- !, | |
190 | kodkod_type_as_list(T,Env,Typelist), | |
191 | create_empty_set(Typelist,Empty). | |
192 | kodkod_translate2(partition(Set,Subsets),_,_,Env,and(KEquals,KDisjunct)) :- !, | |
193 | kodkod_translate_l([Set|Subsets],Env,[KSet|KSubsets]), | |
194 | kodkod_extension_set(KSubsets,KUnion), | |
195 | KEquals = equals(KSet,KUnion), | |
196 | all_disjunct(KSubsets,KDisjunct). | |
197 | kodkod_translate2(convert_bool(BCond),boolean,_,Env,if(KCond,KTrue,KFalse)) :- !, | |
198 | kodkod_translate1(BCond,Env,KCond), | |
199 | kodkod_translate2(boolean_true,boolean,[],Env,KTrue), | |
200 | kodkod_translate2(boolean_false,boolean,[],Env,KFalse). | |
201 | kodkod_translate2(concat(BA,BB),_,_,Env,union(KA,join(Adder,KB))) :- !, | |
202 | % To compute A^B, we use a form A \/ Adder[B] | |
203 | kodkod_translate1(BA,Env,KA), | |
204 | kodkod_translate1(BB,Env,KB), | |
205 | intset_relation_kodkod_name(I), | |
206 | % Adder is a set of the form {a,b | a=b+card(A)} | |
207 | Adder = comp([decl(lhr,1,one,relref(I)),decl(rhr,1,one,relref(I))], | |
208 | equals(sum(varref(lhr)),add(sum(varref(rhr)),card(KA)))). | |
209 | kodkod_translate2(value(V),Type,_Info,Env,K) :- ground(V), %print(try_translate_value(V)),nl, | |
210 | translate_value_to_kodkod(Type,Env,V,K),!. | |
211 | kodkod_translate2(value(Val),Type,Infos,Env,K) :- | |
212 | was_identifier(Val,Infos,ID),!, % identifier was compiled to value; this is a bit dangerous; we should ensure that the identifier ID is used only once | |
213 | %print(kodkod_value_as_id(V,ID)),nl, | |
214 | kodkod_translate2(identifier(ID),Type,Infos,Env,K). | |
215 | kodkod_translate2(event_b_identity,set(couple(Type,Type)),Info,Env,K) :- !, | |
216 | create_maximal_type_set(Type,TSet), | |
217 | kodkod_translate2(identity(TSet),set(couple(Type,Type)),Info,Env,K). | |
218 | kodkod_translate2(external_pred_call('LEQ_SYM',_),Type,Info,Env,K) :- !, | |
219 | kodkod_translate2(truth,Type,Info,Env,K). | |
220 | kodkod_translate2(external_pred_call('LEQ_SYM_BREAK',_),Type,Info,Env,K) :- !, | |
221 | kodkod_translate2(truth,Type,Info,Env,K). | |
222 | kodkod_translate2(Expr,_,Info,Env,Result) :- | |
223 | functor(Expr,Functor,Arity), | |
224 | functor(Tmp,Functor,Arity), | |
225 | kodkod_short(Tmp,_,SC),!, | |
226 | check_side_condition(SC,Expr,Info), | |
227 | Expr =.. [Functor|Args], | |
228 | same_length(Args,TArgs), | |
229 | Lookup =.. [Functor|TArgs], | |
230 | kodkod_translate_l(Args,Env,TArgs), | |
231 | kodkod_short(Lookup,Result,_). | |
232 | kodkod_translate2(E,T,I,_,_) :- | |
233 | create_texpr(E,T,I,TE), | |
234 | %print(expr(E,T)),nl, | |
235 | throw(kodkod(unsupported_expression(TE))). | |
236 | ||
237 | was_identifier(_V,Infos,ID) :- member(was_identifier(ID),Infos). | |
238 | was_identifier(Val,_,GS) :- nonvar(Val), Val=global_set(GS). | |
239 | ||
240 | check_side_condition(none,_Expr,_). | |
241 | check_side_condition(cond(_,_),Expr,Info) :- | |
242 | kodkod_short(Expr,_,cond(Msg,Condition)), | |
243 | ( call(Condition) -> true | |
244 | ; | |
245 | translate_bexpression(Expr,PPExpr), | |
246 | throw(kodkod(side_condition(Msg,PPExpr,Info)))). | |
247 | ||
248 | translate_value_to_kodkod(integer,_Env,int(I),int(I)) :- !. | |
249 | translate_value_to_kodkod(set(Type),Env,V,K) :- !, | |
250 | kodkod_type_as_list(Type,Env,Typelist), | |
251 | expand_custom_set_to_list(V,List), | |
252 | maplist(translate_value_to_kodkod1(Type,Env),List,KList), | |
253 | ( KList = [] -> create_empty_set(Typelist,K) | |
254 | ; KList = [H|T] -> foldl(union_kvalues,T,H,K)). | |
255 | translate_value_to_kodkod(Type,Env,V,K) :- | |
256 | translate_value_to_kodkod1(Type,Env,V,K). | |
257 | ||
258 | :- use_module(probsrc(b_global_sets),[is_b_global_constant/3]). | |
259 | translate_value_to_kodkod1(integer,_Env,int(I),int(I):rel([IntAtoms])) :- !, | |
260 | intset_relation_kodkod_name(IntAtoms). | |
261 | translate_value_to_kodkod1(couple(TA,TB),Env,(A,B),product(KA,KB)) :- !, | |
262 | translate_value_to_kodkod1(TA,Env,A,KA), | |
263 | translate_value_to_kodkod1(TB,Env,B,KB). | |
264 | translate_value_to_kodkod1(global(GS),Env,fd(Nr,GS),Res) :- !, | |
265 | is_b_global_constant(GS,Nr,CstId), | |
266 | lookup_id_relation(CstId,Env,Relname,_KTypes), Res=relref(Relname). | |
267 | translate_value_to_kodkod1(boolean,Env,Val,KodkodResult) :- !, | |
268 | translate_boolean(Val,Env,KodkodResult). | |
269 | translate_value_to_kodkod1(Type,_,_,_) :- | |
270 | format('Cannot translate type in value/1 to kodkod: ~w~n',[Type]),fail. | |
271 | ||
272 | translate_boolean(pred_true,Env,relref(Relname)) :- | |
273 | lookup_id_relation('__kodkod__true',Env,Relname,_KTypes). | |
274 | translate_boolean(pred_false,Env,relref(Relname)) :- | |
275 | lookup_id_relation('__kodkod__false',Env,Relname,_KTypes). | |
276 | ||
277 | union_kvalues(A,B,union(A,B)). | |
278 | ||
279 | create_empty_set([Type],R) :- !,R=empty:rel([Type]). | |
280 | create_empty_set([Type|Rest],product(empty:rel([Type]),R)) :- | |
281 | create_empty_set(Rest,R). | |
282 | ||
283 | :- use_module(probsrc(error_manager),[add_warning/3]). | |
284 | ||
285 | kodkod_short(B,K,none) :- kodkod_short(B,K),!. | |
286 | kodkod_short(B,K,cond(Msg,Cond)) :- kodkod_short(B,K,Msg,Cond). | |
287 | ||
288 | kodkod_short(truth,true). | |
289 | kodkod_short(falsity,false). | |
290 | kodkod_short(negation(A),not(A)). | |
291 | kodkod_short(conjunct(A,B),and(A,B)). | |
292 | kodkod_short(disjunct(A,B), or(A,B)). | |
293 | kodkod_short(implication(A,B),implies(A,B)). | |
294 | kodkod_short(equivalence(A,B), iff(A,B)). | |
295 | ||
296 | kodkod_short(equal(A,B),equals(A,B)). | |
297 | ||
298 | kodkod_short(member(A,B),in(A,B)). | |
299 | kodkod_short(subset(A,B),K) :- kodkod_short(member(A,B),K). | |
300 | kodkod_short(not_subset(A,B),not(K)) :- kodkod_short(subset(A,B),K). | |
301 | kodkod_short(subset_strict(A,B),and(in(A,B),not(equals(A,B)))). | |
302 | kodkod_short(not_subset_strict(A,B),or(not(in(A,B)),equals(A,B))). | |
303 | ||
304 | kodkod_short(cartesian_product(A,B),product(A,B)). | |
305 | kodkod_short(intersection(A,B),intersection(A,B)). | |
306 | kodkod_short(union(A,B),union(A,B)). | |
307 | kodkod_short(closure(E),closure(E)). | |
308 | kodkod_short(set_subtraction(A,B),difference(A,B)). | |
309 | kodkod_short(overwrite(A,B),overwrite(A,B)). | |
310 | kodkod_short(couple(A,B),product(A,B)). | |
311 | ||
312 | kodkod_short(card(X),card(X)). | |
313 | kodkod_short(size(X),card(X)). | |
314 | kodkod_short(greater(A,B),gt(A,B)). | |
315 | kodkod_short(greater_equal(A,B),gte(A,B)). | |
316 | kodkod_short(less(A,B),lt(A,B)). | |
317 | kodkod_short(less_equal(A,B),lte(A,B)). | |
318 | ||
319 | kodkod_short(add(A,B),add(A,B)). | |
320 | kodkod_short(minus(A,B),sub(A,B)). | |
321 | kodkod_short(multiplication(A,B),mul(A,B)). | |
322 | kodkod_short(div(A,B),div(A,B)). | |
323 | kodkod_short(floored_div(A,B),div(A,B)) :- | |
324 | add_warning(kodkod_translate,'Translating floored division as truncated division: ',div(A,B)). | |
325 | kodkod_short(modulo(A,B),mod(A,B)). | |
326 | kodkod_short(unary_minus(A),sub(int(0),A)). | |
327 | %kodkod_short(event_b_identity,iden). % this leads to error in test 711; maybe iden is the function over all types | |
328 | ||
329 | kodkod_short(identity(A),intersection(product(A,A),iden), | |
330 | 'Identity is supported only on unary sets', | |
331 | side_condition_type_arity(A,1)). | |
332 | kodkod_short(reflexive_closure(A),closure(union(intersection(product(All,All),iden),A)), | |
333 | 'Reflexive closure is supported only on binary relations on unary sets', | |
334 | side_condition_type_arity(A,2)) :- All=union(prj([0],A),prj([1],A)). | |
335 | ||
336 | :- public side_condition_type_arity/2. | |
337 | side_condition_type_arity(Expr,Arity) :- | |
338 | get_texpr_type(Expr,Type), | |
339 | type_arity(Type,Arity). | |
340 | ||
341 | kodkod_translate_l([],_,[]). | |
342 | kodkod_translate_l([E|ERest],Env,[K|KRest]) :- | |
343 | kodkod_translate1(E,Env,K), | |
344 | kodkod_translate_l(ERest,Env,KRest). | |
345 | ||
346 | kodkod_translate_binary_membership(partial_function(D,R),F,T,Info,pfunc(F,D,R)) :- is_binary_relation(T,Info). | |
347 | kodkod_translate_binary_membership(total_function(D,R),F,T,Info,func(F,D,R)) :- is_binary_relation(T,Info). | |
348 | kodkod_translate_binary_membership(partial_injection(D,R),F,T,Info,and(pfunc(F,D,R),Inj)) :- | |
349 | is_binary_relation(T,Info),k_is_injective(F,Inj). | |
350 | kodkod_translate_binary_membership(total_injection(D,R),F,T,Info,and(func(F,D,R),Inj)) :- | |
351 | is_binary_relation(T,Info),k_is_injective(F,Inj). | |
352 | kodkod_translate_binary_membership(partial_surjection(D,R),F,T,Info,and(pfunc(F,D,R),Surj)) :- | |
353 | is_binary_relation(T,Info),k_is_surjective(F,R,T,Surj). | |
354 | kodkod_translate_binary_membership(total_surjection(D,R),F,T,Info,and(func(F,D,R),Surj)) :- | |
355 | is_binary_relation(T,Info),k_is_surjective(F,R,T,Surj). | |
356 | kodkod_translate_binary_membership(partial_bijection(D,R),F,T,Info,and(pfunc(F,D,R),Bij)) :- | |
357 | is_binary_relation(T,Info),k_is_bijective(F,R,T,Bij). | |
358 | kodkod_translate_binary_membership(total_bijection(D,R),F,T,Info,and(func(F,D,R),Bij)) :- | |
359 | is_binary_relation(T,Info),k_is_bijective(F,R,T,Bij). | |
360 | kodkod_translate_binary_membership(total_relation(D,R),F,set(T),_Info,and(equals(Dom,D),in(Ran,R))) :- | |
361 | kodkod_domain(F,T,Dom), kodkod_range(F,T,Ran). | |
362 | kodkod_translate_binary_membership(surjection_relation(D,R),F,set(T),_Info,and(in(Dom,D),equals(Ran,R))) :- | |
363 | kodkod_domain(F,T,Dom), kodkod_range(F,T,Ran). | |
364 | ||
365 | is_binary_relation(Type,_) :- type_arity(Type,2),!. | |
366 | is_binary_relation(Type,Info) :- | |
367 | pretty_type(Type,PType), | |
368 | throw(kodkod(side_condition('Functions are only supported for binary relations',PType,Info))). | |
369 | ||
370 | k_is_injective(F,in(join(F,transpose(F)),iden)). | |
371 | k_is_surjective(F,R,set(Type),in(R,Range)) :- | |
372 | kodkod_range(F,Type,Range). | |
373 | k_is_bijective(F,R,Type,and(Inj,Surj)) :- | |
374 | k_is_injective(F,Inj), k_is_surjective(F,R,Type,Surj). | |
375 | ||
376 | kodkod_domain(KRel,BType,prj(Positions,KRel)) :- | |
377 | remove_optional_set(BType,couple(DType,_RType)), | |
378 | type_arity(DType,Arity),enumerate(Arity,0,Positions). | |
379 | kodkod_range(KRel,BType,prj(Positions,KRel)) :- | |
380 | remove_optional_set(BType,couple(DType,RType)), | |
381 | type_arity(DType,Start),type_arity(RType,Arity), | |
382 | enumerate(Arity,Start,Positions). | |
383 | ||
384 | % function application / relational image | |
385 | % kodkod_function_application(+BFun,+BArg,+Env,-K): | |
386 | % translate a function application f(x) where BFun is f and x is BArg to Kodkod | |
387 | % Usually a function application f(x) can be translated to join(kx,kf) | |
388 | % when kx is unary. But for n-ary kx (n>1) we have to apply several joins manually | |
389 | kodkod_function_application(BFun,BArg,Env,K) :- | |
390 | kodkod_translate1(BFun,Env,KFun), | |
391 | kodkod_translate1(BArg,Env,KArg), | |
392 | get_texpr_type(BArg,ArgType), type_arity(ArgType,ArgArity), | |
393 | get_texpr_type(BFun,FunType), type_arity(FunType,FunArity), | |
394 | kodkod_function_application_aux(ArgArity,FunArity,KFun,KArg,K). | |
395 | kodkod_function_application_aux(1,_,KFun,KArg,K) :- !, | |
396 | K = join(KArg,KFun). | |
397 | kodkod_function_application_aux(ArgArity,FunArity,KFun,KArg,K) :- | |
398 | % We translate f(x) resp. f[{x}] to | |
399 | % prj( nx..(nf-1), { e : f | prj( 0..(nx-1), e ) = x } ) | |
400 | % with nf resp. nx being the arity of f resp. x | |
401 | K = prj(RightPos,CompSet), | |
402 | CompSet = comp([decl(KId,FunArity,one,KFun)],equals(prj(LeftPos,varref(KId)),KArg)), | |
403 | % LeftPos is 0..(nx-1) (contains ArgArity elements starting with 0) | |
404 | enumerate(ArgArity,0,LeftPos), | |
405 | % RightPos is nx..(nf-1) (contains FunArity-ArgArity elements starting with nx) | |
406 | RemainingPos is FunArity-ArgArity, | |
407 | enumerate(RemainingPos,ArgArity,RightPos), | |
408 | % e is some unique identifier | |
409 | unique_identifier(KId). | |
410 | ||
411 | kodkod_reverse(BArg,Env,K) :- | |
412 | kodkod_translate1(BArg,Env,KArg), | |
413 | get_texpr_type(BArg,ArgType), type_arity(ArgType,ArgArity), | |
414 | kodkod_reverse_aux(ArgArity,KArg,K). | |
415 | kodkod_reverse_aux(2,KArg,transpose(KArg)) :- !. | |
416 | kodkod_reverse_aux(Arity,KArg,prj(Rev,KArg)) :- | |
417 | enumerate(Arity,0,Positions), | |
418 | reverse(Positions,Rev). | |
419 | ||
420 | ||
421 | % two-phase handling of declarations in forall, exists, etc. | |
422 | kodkod_declarations1([],SubEnv,SubEnv,[]). | |
423 | kodkod_declarations1([TExpr|IRest], | |
424 | Env,Env2, | |
425 | [provdecl(KId,Type,Analysis)|DRest]) :- | |
426 | get_texpr_id(TExpr,Id), | |
427 | get_texpr_type(TExpr,Type), | |
428 | get_texpr_info(TExpr,Info), | |
429 | (memberchk(analysis(Analysis),Info) -> true ; Analysis=[]), | |
430 | unique_identifier(v,Id,KId), | |
431 | add_var_to_environment(Id,KId,Env,SubEnv), | |
432 | kodkod_declarations1(IRest,SubEnv,Env2,DRest). | |
433 | ||
434 | kodkod_declarations2([],_,KCond,KCond,[]). | |
435 | kodkod_declarations2([provdecl(KId,Type,Analysis)|PRest], | |
436 | Env,KCond,KCond2, | |
437 | [decl(KId,Arity,Mult,Expr)|DRest]) :- | |
438 | type_arity(Type,Arity), | |
439 | kodkod_declaration(Type,KId,Analysis,Env,KCond,NewKCond,Mult,Expr), | |
440 | kodkod_declarations2(PRest,Env,NewKCond,KCond2,DRest). | |
441 | kodkod_declaration(integer,_KId,_Analysis,_Env,KCond,KCond,Mult,Expr) :- | |
442 | % TODO: we have to make a decision whether a quantified integer | |
443 | % variable should be the bit-representation of the value | |
444 | % (for variables that can take large values) | |
445 | % or a the item of the integer relation. | |
446 | % currently we do only the latter: | |
447 | !,Mult = one, | |
448 | intset_relation_kodkod_name(IntsetRelation), | |
449 | Expr = relref(IntsetRelation). | |
450 | kodkod_declaration(Type,KId,_Analysis,Env,KCond,NewKCond,Mult,Expr) :- | |
451 | (Type=set(_) -> Mult=set; Mult=one), | |
452 | ( find_in(KCond,KId,Expr,NewKCond) -> | |
453 | true | |
454 | ; | |
455 | % here we have to insert a possible choice for | |
456 | % integer variables. That possible choice should be returned | |
457 | % as a variable and later its value determine the outcome | |
458 | % of the choice. | |
459 | kodkod_type(Type,Env,Expr), | |
460 | NewKCond = KCond). | |
461 | ||
462 | find_in(Formula,Id,Expression,NewFormula) :- | |
463 | disassemble_conjunction(Formula,Parts), | |
464 | find_in2(Parts,Id,Expression,Rest), | |
465 | kodkod_conjunction(Rest,NewFormula). | |
466 | find_in2([in(varref(Id),Expr)|Rest], Id, Expr, Rest) :- !. | |
467 | find_in2([Pred|Rest], Id, Expr, [Pred|Result]) :- | |
468 | find_in2(Rest,Id,Expr,Result). | |
469 | ||
470 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
471 | % A Kodkod environment contains two maps: | |
472 | % a) The first one maps Kodkod types to references to relations that will | |
473 | % represents all elements to the given type | |
474 | % b) The second one maps an identifier to a reference to the relations that | |
475 | % represents the variable in | |
476 | ||
477 | %kodkod_subenv(Id,Ref,kenv(Types,OldBinds),kenv(Types,NewBinds)) :- | |
478 | % avl_store(Id,OldBinds,Ref,NewBinds). | |
479 | ||
480 | % End: Environment | |
481 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
482 | ||
483 | kodkod_type(T,Env,K) :- | |
484 | remove_optional_set(T,T2), | |
485 | kodkod_type2(T2,T2,Env,K). | |
486 | kodkod_type2(couple(A,B),_,Env,product(KA,KB)) :- !, | |
487 | kodkod_type2(A,A,Env,KA), | |
488 | kodkod_type2(B,B,Env,KB). | |
489 | kodkod_type2(Type,_,Env,relref(Ref)) :- | |
490 | lookup_type_relation(Type,Env,Ref),!. | |
491 | kodkod_type2(_,T,_Env,_Ref) :- | |
492 | throw(kodkod(unsupported_type(T))). | |
493 | ||
494 | kodkod_type_as_list(T,Env,TypeList) :- | |
495 | remove_optional_set(T,T2), | |
496 | kodkod_type_as_list2(T2,Env,TypeList). | |
497 | kodkod_type_as_list2(couple(A,B),Env,TypeList) :- !, | |
498 | kodkod_type_as_list2(A,Env,ATL), | |
499 | kodkod_type_as_list2(B,Env,BTL), | |
500 | append(ATL,BTL,TypeList). | |
501 | kodkod_type_as_list2(BType,Env,[KType]) :- | |
502 | lookup_type_relation(BType,Env,KType). | |
503 | ||
504 | remove_optional_set(set(A),B) :- !,A=B. | |
505 | remove_optional_set(T,T). | |
506 | ||
507 | type_arity(set(T),A) :- type_arity(T,A). | |
508 | type_arity(integer,1). | |
509 | type_arity(boolean,1). | |
510 | type_arity(global(_),1). | |
511 | type_arity(couple(A,B),Arity) :- | |
512 | type_arity(A,AA),type_arity(B,AB),Arity is AA+AB. | |
513 | ||
514 | % extension sets | |
515 | kodkod_extension_set([],none) :- !. | |
516 | kodkod_extension_set([Elem],Elem) :- !. | |
517 | kodkod_extension_set([Elem|Rest],union(Elem,Ext)) :- | |
518 | kodkod_extension_set(Rest,Ext). | |
519 | ||
520 | all_disjunct(Sets,K) :- | |
521 | all_disjunct2(Sets,Dis,[]), | |
522 | kodkod_conjunction(Dis,K). | |
523 | all_disjunct2([]) --> !. | |
524 | all_disjunct2([S|Rest]) --> | |
525 | all_disjunct3(Rest,S), | |
526 | all_disjunct2(Rest). | |
527 | all_disjunct3([],_) --> !. | |
528 | all_disjunct3([B|Rest],A) --> | |
529 | [no(intersection(A,B))], | |
530 | all_disjunct3(Rest,A). | |
531 | ||
532 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
533 | % helper predicates | |
534 | ||
535 | ||
536 | enumerate(0,_,[]) :- !. | |
537 | enumerate(N,S,[S|Rest]) :- N2 is N-1, S2 is S+1, enumerate(N2,S2,Rest). | |
538 |