1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
open Typed
open Commands
open Format
open Options
module E = Expr
module Ex = Explanation
module type S = sig
type sat_env
type used_context
type status =
| Unsat of Commands.sat_tdecl * Ex.t
| Inconsistent of Commands.sat_tdecl
| Sat of Commands.sat_tdecl * sat_env
| Unknown of Commands.sat_tdecl * sat_env
| Timeout of Commands.sat_tdecl option
| Preprocess
val process_decl:
(status -> int64 -> unit) ->
used_context ->
sat_env * bool * Ex.t -> Commands.sat_tdecl ->
sat_env * bool * Ex.t
val print_status : status -> int64 -> unit
val init_all_used_context : unit -> used_context
val choose_used_context : used_context -> goal_name:string -> used_context
end
module Make(SAT : Sat_solver_sig.S) : S with type sat_env = SAT.t = struct
type sat_env = SAT.t
type used_context = Util.SS.t option
type status =
| Unsat of Commands.sat_tdecl * Ex.t
| Inconsistent of Commands.sat_tdecl
| Sat of Commands.sat_tdecl * sat_env
| Unknown of Commands.sat_tdecl * sat_env
| Timeout of Commands.sat_tdecl option
| Preprocess
let output_used_context g_name dep =
if not (Options.js_mode ()) then begin
let f = Options.get_used_context_file () in
let cout = open_out (sprintf "%s.%s.used" f g_name) in
let cfmt = Format.formatter_of_out_channel cout in
Ex.print_unsat_core cfmt dep;
close_out cout
end
let check_produced_unsat_core dep =
if verbose () then
fprintf fmt "checking the unsat-core:\n-------------------\n%a@."
(Ex.print_unsat_core ~tab:false) dep;
try
let pb = E.Set.elements (Ex.formulas_of dep) in
let env =
List.fold_left
(fun env f ->
SAT.assume env
{E.ff=f;
origin_name = "";
gdist = -1;
hdist = -1;
trigger_depth = max_int;
nb_reductions = 0;
age=0;
lem=None;
mf=false;
gf=false;
from_terms = [];
theory_elim = true;
} Ex.empty
) (SAT.empty ()) pb
in
ignore (SAT.unsat
env
{E.ff=E.vrai;
origin_name = "";
gdist = -1;
hdist = -1;
trigger_depth = max_int;
nb_reductions = 0;
age=0;
lem=None;
mf=false;
gf=false;
from_terms = [];
theory_elim = true;
});
fprintf fmt "Checking produced unsat-core failed!@.";
fprintf fmt "this may be due to a bug.@.";
exit 1
with
| SAT.Unsat _ -> ()
| (SAT.Sat _ | SAT.I_dont_know _) as e -> raise e
let unused_context name context =
match context with
| None -> false
| Some s -> not (Util.SS.mem name s)
let mk_root_dep f_name =
if Options.unsat_core () then Ex.singleton (Ex.RootDep f_name)
else Ex.empty
let process_decl print_status used_context ((env, consistent, dep) as acc) d =
try
match d.st_decl with
| Assume(n, f, mf) ->
let is_hyp = try (Char.equal '@' n.[0]) with _ -> false in
if not is_hyp && unused_context n used_context then
acc
else
let dep = if is_hyp then Ex.empty else mk_root_dep n in
if consistent then
SAT.assume env
{E.ff=f;
origin_name = n;
gdist = -1;
hdist = (if is_hyp then 0 else -1);
trigger_depth = max_int;
nb_reductions = 0;
age=0;
lem=None;
mf=mf;
gf=false;
from_terms = [];
theory_elim = true;
} dep,
consistent, dep
else env, consistent, dep
| PredDef (f, name) ->
if unused_context name used_context then acc
else
let dep = mk_root_dep name in
SAT.pred_def env f name dep d.st_loc, consistent, dep
| RwtDef _ -> assert false
| Query(n, f, sort) ->
let dep =
if consistent then
let dep' = SAT.unsat env
{E.ff=f;
origin_name = n;
hdist = -1;
gdist = 0;
trigger_depth = max_int;
nb_reductions = 0;
age=0;
lem=None;
mf=(sort != Check);
gf=true;
from_terms = [];
theory_elim = true;
} in
Ex.union dep' dep
else dep
in
if debug_unsat_core () then check_produced_unsat_core dep;
if save_used_context () then output_used_context n dep;
print_status (Unsat (d, dep)) (SAT.get_steps ());
env, false, dep
| ThAssume ({ Expr.ax_name; _ } as th_elt) ->
if unused_context ax_name used_context then
acc
else
if consistent then
let dep = mk_root_dep ax_name in
let env = SAT.assume_th_elt env th_elt dep in
env, consistent, dep
else env, consistent, dep
with
| SAT.Sat t ->
print_status (Sat (d,t)) (SAT.get_steps ());
if model () then SAT.print_model ~header:true std_formatter t;
env , consistent, dep
| SAT.Unsat dep' ->
let dep = Ex.union dep dep' in
if debug_unsat_core () then check_produced_unsat_core dep;
print_status (Inconsistent d) (SAT.get_steps ());
env , false, dep
| SAT.I_dont_know t ->
print_status (Unknown (d, t)) (SAT.get_steps ());
if model () then SAT.print_model ~header:true std_formatter t;
env , consistent, dep
| Util.Timeout as e ->
print_status (Timeout (Some d)) (SAT.get_steps ());
raise e
let goal_name d =
match d.st_decl with
| Query(n,_,_) -> sprintf " (goal %s)" n
| _ -> ""
let print_status_unsat_mode status steps =
let time = Time.value() in
match status with
| Unsat (d, dep) ->
let loc = d.st_loc in
if Options.answers_with_locs () then
eprintf "; %aValid (%2.4f) (%Ld steps)%s@."
Loc.report loc time steps (goal_name d);
printf "unsat@.";
if unsat_core() && not (debug_unsat_core()) && not (save_used_context())
then
printf "(\n%a)@." (Ex.print_unsat_core ~tab:true) dep
| Inconsistent _ ->
()
| Unknown (d, _) ->
let loc = d.st_loc in
if Options.answers_with_locs () then
eprintf "; %aI don't know (%2.4f) (%Ld steps)%s@."
Loc.report loc time steps (goal_name d);
printf "unknown@."
| Sat (d, _) ->
let loc = d.st_loc in
if Options.answers_with_locs () then
eprintf "; %aInvalid (%2.4f) (%Ld steps)%s@."
Loc.report loc time steps (goal_name d);
printf "sat@."
| Timeout (Some d) ->
let loc = d.st_loc in
if Options.answers_with_locs () then
eprintf "; %aTimeout (%2.4f) (%Ld steps)%s@."
Loc.report loc time steps (goal_name d);
printf "timeout@."
| Timeout None ->
if Options.answers_with_locs () then
eprintf "; %aTimeout (%2.4f) (%Ld steps)@."
Loc.report Loc.dummy time steps;
printf "timeout@."
| Preprocess ->
if Options.answers_with_locs () then
eprintf "; %aPreprocessing (%2.4f) (%Ld steps)@."
Loc.report Loc.dummy time steps
let print_status_valid_mode status steps =
let time = Time.value() in
let report_loc fmt loc =
if js_mode () then fprintf fmt "# [answer] "
else if Options.answers_with_locs () then Loc.report fmt loc
in
match status with
| Unsat (d, dep) ->
let loc = d.st_loc in
printf "%aValid (%2.4f) (%Ld steps)%s@."
report_loc loc time steps (goal_name d);
if unsat_core() && not (debug_unsat_core()) && not (save_used_context())
then
printf "unsat-core:\n%a@." (Ex.print_unsat_core ~tab:true) dep
| Inconsistent d ->
let loc = d.st_loc in
if Options.verbose () then
eprintf "%aInconsistent assumption@." report_loc loc
| Sat (d, _) ->
let loc = d.st_loc in
printf "%aInvalid (%2.4f) (%Ld steps)%s@."
report_loc loc time steps (goal_name d)
| Unknown (d, _) ->
let loc = d.st_loc in
printf "%aI don't know (%2.4f) (%Ld steps)%s@."
report_loc loc time steps (goal_name d)
| Timeout (Some d) ->
let loc = d.st_loc in
printf "%aTimeout (%2.4f) (%Ld steps)%s@."
report_loc loc time steps (goal_name d);
| Timeout None ->
printf "%aTimeout (%2.4f) (%Ld steps)@."
report_loc Loc.dummy time steps;
| Preprocess ->
printf "%aPreprocessing (%2.4f) (%Ld steps)@."
report_loc Loc.dummy time steps
let print_status status steps =
if Options.unsat_mode () then print_status_unsat_mode status steps
else print_status_valid_mode status steps
let init_with_replay_used acc f =
assert (Sys.file_exists f);
let cin = open_in f in
let acc = ref (match acc with None -> Util.SS.empty | Some ss -> ss) in
try
while true do acc := Util.SS.add (input_line cin) !acc done;
assert false
with End_of_file ->
Some !acc
let init_used_context ~goal_name =
if Options.replay_used_context () then
let uc_f =
sprintf "%s.%s.used" (Options.get_used_context_file ()) goal_name
in
if Sys.file_exists uc_f then init_with_replay_used None uc_f
else
begin
fprintf fmt
"File %s not found! Option -replay-used will be ignored@." uc_f;
None
end
else
None
let init_all_used_context () =
if Options.replay_all_used_context () then
let dir = Filename.dirname (Options.get_used_context_file ()) in
Array.fold_left
(fun acc f ->
let f = sprintf "%s/%s" dir f in
if (Filename.check_suffix f ".used") then init_with_replay_used acc f
else acc
) None (Sys.readdir dir)
else None
let choose_used_context all_ctxt ~goal_name =
if Options.replay_all_used_context () then all_ctxt
else init_used_context ~goal_name
end