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_process, [register_problem/7, kodkod_request_intern/5,
6 get_original_problem/2,
7 clear_java_comp_time/0,
8 get_java_comp_time/1,
9 stop_kodkod/0
10 ]).
11
12 :- use_module(library(avl)).
13 :- use_module(library(lists)).
14 :- use_module(library(process)).
15 :- use_module(library(file_systems)).
16
17 :- use_module(probsrc(module_information),[module_info/2]).
18 :- use_module(probsrc(store), [lookup_value_for_existing_id/4]).
19 :- use_module(probsrc(bsyntaxtree)).
20 :- use_module(probsrc(kernel_objects), [equal_object/2]).
21 :- use_module(probsrc(custom_explicit_sets), [expand_custom_set_to_list/2]).
22 :- use_module(probsrc(error_manager)).
23 :- use_module(probsrc(system_call)).
24 :- use_module(probsrc(preferences), [get_preference/2]).
25 :- use_module(probsrc(debug), [debug_format/3]).
26
27 :- use_module(kodkod_printer).
28
29 :- use_module(probsrc(translate),[print_bvalue/1,print_bstate/1]).
30
31 :- module_info(group,kodkod).
32 :- module_info(description,'This is the inter-process communication with the Java process that contains the Kodkod engine.').
33
34 :- dynamic known_problem/7, next_problem_id/1.
35
36 next_problem_id(0).
37
38 register_problem(Ids,KExpr,Idmap,Typemap,Valuemap,Predicate,ProblemId) :-
39 startup_kodkod,
40 get_new_problem_id(ProblemId),
41 extract_all_types(Typemap,Types),
42 extract_all_relations(Idmap,Relations),
43 prepare_value_mapping(Valuemap,ProbToKodkodVal,KodkodToProbVal),
44 prepare_id_mapping(Ids,Idmap,ProbToKodkodId,KodkodToProbId),
45 assert( known_problem(ProblemId,Types,Relations,KExpr,
46 probkodkod(ProbToKodkodVal,ProbToKodkodId),
47 kodkodprob(KodkodToProbVal,KodkodToProbId),
48 Predicate) ),
49 catch( send_problem(ProblemId),
50 error(_,_),
51 (reset_kodkod_process,send_problem(ProblemId))).
52
53 get_original_problem(Id,OrigPredicate) :-
54 known_problem(Id,_,_,_,_,_,OrigPredicate).
55
56 extract_all_types(Typemap,Types) :-
57 avl_range(Typemap,Relations),
58 include(is_base_relation,Relations,BaseRelations),
59 %print(extract_int_types(Relations)),nl,
60 extract_int_types(Relations,IntTypes),
61 %print('Result : '), print(IntTypes),nl,
62 append(IntTypes,BaseTypes,Types),
63 maplist(extract_type, BaseRelations, BaseTypes).
64
65 is_base_relation(relation(_,_,reldef(_,_,_,_,_))).
66 extract_type(relation(Id,Size,_Relspec),type(Id,Size)).
67
68 :- use_module(kodkod_tools,[pow2integer_relation_kodkod_name/1]).
69 extract_int_types(Relations,IntTypes) :-
70 exclude(is_base_relation,Relations,IntRelations),
71 extract_int_types2(IntRelations,IntTypes).
72 extract_int_types2([],[]) :- !.
73 extract_int_types2(IntRelations,[inttype(PowName,PowMin,PowMax,IntsetName,Min,Max)]) :-
74 selectchk(relation(IntsetName,_,intsetrel(_Id,RMin,Max)),IntRelations,Rest),!,
75 Min is min(RMin,0),
76 extract_int_types2(Rest,RestResult),
77 (RestResult = [inttype(PowName,PowMin,PowMax)] -> true
78 ; RestResult = [] -> kodkod_tools:pow2integer_relation_kodkod_name(PowName),
79 PowMin=Min, PowMax=Max % I have no idea if this is correct; TO DO: Daniel check this
80 ). % What if RestResult is something else ???
81 extract_int_types2(IntRelations,[inttype(PowName,PowMin,PowMax)]) :-
82 memberchk(relation(PowName,_,pow2rel(_Id,RPowMin,PowMax)),IntRelations),!,
83 PowMin is min(RPowMin,0).
84
85 prepare_id_mapping(Ids,Idmap,ProbToKodkod,KodkodToProb) :-
86 prepare_id_mapping2(Ids,Idmap,ProbToKodkod,KodkodToProbList),
87 list_to_avl(KodkodToProbList, KodkodToProb).
88 prepare_id_mapping2([],_,[],[]).
89 prepare_id_mapping2([TId|Rest],Idmap,[PK|ProbToKodkod],[KP|KodkodToProb]) :-
90 prepare_id_mapping3(TId,Idmap,PK,KP),
91 prepare_id_mapping2(Rest,Idmap,ProbToKodkod,KodkodToProb).
92 prepare_id_mapping3(TId,Idmap,bid(BType,P)-K,K-bid(BType,P)) :-
93 get_texpr_id(TId,P),
94 get_texpr_type(TId,BType1),
95 adapt_seq_type(BType1,BType),
96 avl_fetch(P,Idmap,reldef(K,_Types,_SetOrSingle,_ExactOrSubset,_Set)).
97
98 adapt_seq_type(seq(T),S) :- !,S=set(couple(integer,T)).
99 adapt_seq_type(T,T).
100
101 prepare_value_mapping(Valuemap,ProbToKodkod,KodkodToProb) :-
102 avl_to_list(Valuemap,ProbKodkodList),
103 maplist(reverse_key_value, ProbKodkodList, KodkodProbList),
104 list_to_avl(KodkodProbList,KodkodToProb),
105 maplist(remove_type_info,ProbKodkodList, L1),
106 list_to_avl(L1,ProbToKodkod).
107 reverse_key_value((T:P)-K, (T:K)-P).
108 remove_type_info((_T:P)-K, P-K).
109
110 get_new_problem_id(ProblemId) :-
111 retract(next_problem_id(Id)),
112 NextId is Id+1,
113 assert(next_problem_id(NextId)),
114 ProblemId = Id.
115
116 extract_all_relations(Idmap,Relations) :- avl_range(Idmap,Relations).
117
118 send_problem(Id) :-
119 kodkod_process(_,KOut,_),
120 known_problem(Id,Types,Relations,Formula,_ToKodkod,_ToProB,_OrigPredicate),
121 get_preference(time_out,TO),
122 get_preference(kodkod_symmetry_level,Symmetry),
123 get_preference(kodkod_sat_solver,Solver),
124 kodkod_printer:kkp_problem(KOut,TO,Symmetry,Solver,Id,problem(Types,Relations,Formula,xxx,none)).
125
126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
127 % communication with external java process
128 :- dynamic kodkod_process/3.
129
130 reset_kodkod_process :- retractall(kodkod_process(_,_,_)).
131
132 startup_kodkod :- kodkod_process(_,_,_), !.
133 startup_kodkod :-
134 absolute_file_name(prob_lib('.'), KodkodDir),
135 kodkod_jar(KodkodJar),
136
137 atom_concat('-Djava.library.path=', KodkodDir, JLibpath),
138
139 get_command_path('java',CmdPath),
140
141 %format('Starting Kodkod JAR ~w using ~w~n',[KodkodJar,JLibpath]),
142 get_preference(kodkod_sat_solver,Solver),
143
144 process_create(CmdPath,
145 [JLibpath, '-Xmx1024M','-jar', KodkodJar,Solver],
146 [process(KProc),stdout(pipe(KIn)),stdin(pipe(KOut))]),
147 check_correct_startup(KIn),
148
149 assert(kodkod_process(KProc,KOut,KIn)).
150
151 check_correct_startup(S) :-
152 catch( (read_line(S,Line),check_first_line(Line)),
153 E,
154 add_error_and_fail(kodkod_process, 'Exception while connecting to Kodkod process', E)).
155 check_first_line(Line) :-
156 append("ProB-Kodkod started: ",Msg,Line),!,
157 format('Kodkod module started up successfully (SAT solver ~s).~n',[Msg]).
158 check_first_line(_Line) :-
159 add_error_and_fail(kodkod_process,'Unable to start-up Kodkod process.\n').
160
161 kodkod_jar(KodkodJar) :-
162 absolute_file_name(prob_lib('probkodkod.jar'), KodkodJar),
163 ( file_exists(KodkodJar,read) -> true
164 ; otherwise ->
165 add_error_and_fail(kodkod_process,'Unable to read Kodkod library. Please check your installation or disable the use of Kodkod')).
166
167 stop_kodkod :-
168 kodkod_process(PId,KOut,KIn),
169 call_cleanup( (write(KOut, 'stop.\n'), flush_output(KOut) ),
170 ( process_wait(PId,_), close(KOut), close(KIn),
171 retractall(kodkod_process(_,_,_)))).
172
173 %kodkod_problem(Id,Problem) :-
174 % kodkod_process(_,KOut,_),
175 % get_preference(time_out,TO),get_preference(kodkod_symmetry_level,Symmetry),get_preference(kodkod_sat_solver,Solver),
176 % kkp_problem(KOut,TO,Symmetry,Solver,Id,Problem).
177
178 kodkod_request_intern(ProblemId, Signum, MaxNrOfSols, LocalState, State) :-
179 known_problem(ProblemId,_Size,_Relations,_Formula,ToKodkod,ToProB,_OrigPredicate),
180 extract_known_values(ToKodkod,LocalState,State,Known,UnknownList),
181 copy_term(UnknownList,UnknownListCopy),
182 list_to_avl(UnknownListCopy,Unknown),
183 !,
184 debug_println(19,send_kodkod_request(ProblemId,Signum,MaxNrOfSols,Known)),
185 send_request(ProblemId, ToProB, Signum, MaxNrOfSols, Known, Unknown),
186 %describe_sol(UnknownListCopy),
187 UnknownList=UnknownListCopy.
188 %print_bstate(State).
189
190 %describe_sol(List) :-
191 % nl,write('Kodkod solution:'),nl,describe_sol2(List).
192 %describe_sol2([]).
193 %describe_sol2([Id-Value|Rest]) :-
194 % describe_sol3(Id,Value),
195 % describe_sol2(Rest).
196 %describe_sol3(Id,Value) :-
197 % write(Id),write(': '),print_bvalue(Value),nl.
198
199
200 extract_known_values(probkodkod(ValueMap,Ids),LocalState,State,Out,Unknown) :-
201 extract_known_values2(Ids,ValueMap,LocalState,State,Out,[],Unknown,[]).
202 extract_known_values2([],_ValueMap,_LocalState,_State,Known,Known,Unknown,Unknown).
203 extract_known_values2([bid(Type,Prob)-Kodkod|Rest],ValueMap,LocalState,State,
204 KnownIn,KnownOut,UnknownIn,UnknownOut) :-
205 extract_known_value(Type,Prob,Kodkod,ValueMap,LocalState,State,KnownIn,KnownInter,UnknownIn,UnknownInter),
206 extract_known_values2(Rest,ValueMap,LocalState,State,KnownInter,KnownOut,UnknownInter,UnknownOut).
207 extract_known_value(Type,Prob,Kodkod,ValueMap,LocalState,State,KnownIn,KnownOut,UnknownIn,UnknownOut) :-
208 lookup_value_for_existing_id(Prob,LocalState,State,Value),
209 ( ground(Value) ->
210 map_prob_value_to_kodkod(Type,Value,ValueMap,KValue),
211 KnownIn = [kout(Kodkod,KValue)|KnownOut],
212 UnknownIn = UnknownOut
213 ; otherwise ->
214 KnownIn = KnownOut,
215 UnknownIn = [Kodkod-Value|UnknownOut]),!.
216 extract_known_value(_Type,Prob,_Kodkod,_ValueMap,_LocalState,_State,_KnownIn,_KnownOut,_UnknownIn,_UnknownOut) :-
217 add_error_and_fail(kodkod_process,'mapping ProB value to Kodkod failed', Prob).
218
219 map_prob_value_to_kodkod(set(_),Prob,ValueMap,Kodkod) :-
220 !, expand_custom_set_to_list(Prob,List),
221 map_prob_values_to_kodkod(List,ValueMap,Kodkod).
222 map_prob_value_to_kodkod(_Type,Prob,ValueMap,Kodkod) :-
223 map_prob_values_to_kodkod([Prob],ValueMap,Kodkod).
224 map_prob_values_to_kodkod([],_,[]).
225 map_prob_values_to_kodkod([P|Prest],ValueMap,[tuple(K)|Krest]) :-
226 map_prob_value_to_kodkod2(P,ValueMap,K,[]),
227 map_prob_values_to_kodkod(Prest,ValueMap,Krest).
228 map_prob_value_to_kodkod2((A,B),ValueMap) -->
229 !,map_prob_value_to_kodkod2(A,ValueMap),
230 map_prob_value_to_kodkod2(B,ValueMap).
231 map_prob_value_to_kodkod2(int(I),_ValueMap) --> !,[I].
232 map_prob_value_to_kodkod2(Prob,ValueMap) --> [Kodkod],
233 {avl_fetch(Prob,ValueMap,Kodkod)}.
234
235
236 :- use_module(probsrc(debug),[debug_println/2]).
237 send_request(ProblemId, ToProb, Signum, MaxNrOfSols,OutValues, In) :-
238 kodkod_process(_,OStream,IStream),
239 debug:debug_println(19,sending_kodkod_request(ProblemId,Signum,MaxNrOfSols)),
240 kkp_request(ProblemId, Signum, MaxNrOfSols, OutValues, OStream),
241 get_solutions_from_stream(OStream,IStream,ProblemId,MaxNrOfSols,ToProb,In).
242
243 read_rest(ProblemId,MaxNrOfSols,ToProb,In) :-
244 kodkod_process(_,OStream,IStream),
245 kkp_list(ProblemId,MaxNrOfSols,OStream),
246 get_solutions_from_stream(OStream,IStream,ProblemId,MaxNrOfSols,ToProb,In).
247
248 get_solutions_from_stream(OStream,IStream,ProblemId,MaxNrOfSols,ToProB,In) :-
249 flush_output(OStream),
250 read_answer_from_kodkod(IStream,Answer),
251 !,
252 %print(answer_from_stream(Answer)),nl,
253 process_answer(Answer,ProblemId,MaxNrOfSols,ToProB,In).
254
255 % read an answer but skip over statistics infos:
256 read_answer_from_kodkod(IStream,Answer) :-
257 read(IStream,Answer1),
258 (Answer1=stats(T,S,C,V,P) % special statistics info fact
259 -> debug_format(20,'Kodkod Statistics: ~w ms translation, ~w ms solving, ~w clauses, ~w variables, ~w primary variables~n',[T,S,C,V,P]),
260 read_answer_from_kodkod(IStream,Answer)
261 ; Answer=Answer1).
262
263 process_answer(solutions(Sols,More,Times),ProblemId,MaxNrOfSols,ToProb,In) :-
264 format('Times for computing solutions: ~w~n',[Times]),
265 save_java_comp_time(Times),
266 get_solutions(Sols,More,ProblemId,MaxNrOfSols,ToProb,In).
267 process_answer(sat_timeout,ProblemId,_,_ToProb,_In) :-
268 add_warning(kodkod_process,'Kodkod SAT Solver Timeout for Problem Id: ',ProblemId),
269 %throw(time_out). % can only be caught by time_out not by on_exception !
270 throw(enumeration_warning(kodkod_timeout,ProblemId,'','',critical)).
271 process_answer(sat_non_incremental,ProblemId,_,_ToProb,_In) :-
272 add_warning(kodkod_process,'Kodkod SAT Solver is non incremental and cannot compute all solutions for Problem Id: ',ProblemId),
273 throw(enumeration_warning(kodkod_timeout,ProblemId,'','',critical)).
274 process_answer(unknown(_),ProblemId,_,_ToProb,_In) :-
275 add_warning(kodkod_process,'Kodkod SAT Solver error occured for Problem Id: ',ProblemId),
276 throw(enumeration_warning(kodkod_timeout,ProblemId,'','',critical)).
277
278
279 get_solutions(Sols,_More,_ProblemId,_,ToProb,In) :-
280 member(Sol,Sols), get_solution(Sol,ToProb,In).
281 get_solutions(_Sols,more,ProblemId,MaxNrOfSols,ToProb,In) :-
282 read_rest(ProblemId,MaxNrOfSols,ToProb,In).
283
284 get_solution([],_,_).
285 get_solution([Binding|BRest],kodkodprob(VMap,IdMap),BValues) :-
286 ( Binding = b(Name,KValues) -> true
287 ; Binding = s(Name,KValues) -> Type = set(_)),
288 avl_fetch(Name,BValues,BValue),
289 avl_fetch(Name,IdMap,bid(Type,_BName)),
290 map_kodkod_prob(Type,KValues,VMap,Result),!,
291 equal_object(BValue,Result),
292 get_solution(BRest,kodkodprob(VMap,IdMap),BValues).
293
294 map_kodkod_prob(set(Type),Tuples,Map,Value) :-
295 !,map_kodkod_prob2(Tuples,Type,Map,Value).
296 map_kodkod_prob(Type,KValue,Map,BValue) :-
297 map_kodkod_prob2([KValue],Type,Map,[BValue]).
298 map_kodkod_prob2([],_,_,[]).
299 map_kodkod_prob2([Values|TRest],Type,Map,[BValue|BRest]) :-
300 map_kodkod_prob3(Type,Map,BValue,Values,[]),
301 map_kodkod_prob2(TRest,Type,Map,BRest).
302 map_kodkod_prob3(couple(TA,TB),Map,(BA,BB)) -->
303 map_kodkod_prob3(TA,Map,BA),
304 map_kodkod_prob3(TB,Map,BB).
305 map_kodkod_prob3(integer,_,int(Value)) --> !,[Value].
306 map_kodkod_prob3(Type,Map,BValue) -->
307 [K],{avl_fetch(Type:K,Map,BValue),!}.
308
309 :- dynamic java_comp_time/1.
310 clear_java_comp_time :-
311 retractall(java_comp_time(_)).
312 get_java_comp_time(Time) :-
313 findall( T, (java_comp_time(Ts),member(T,Ts)), Times),
314 sumlist(Times,Time).
315 save_java_comp_time(Times) :-
316 assert(java_comp_time(Times)).