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