do not take resource limits from more than one source
[why3.git] / src / why3session / why3session_latex.ml
blob55eed1e46fc402c584bd9399003081cb2bd5d6db
1 (********************************************************************)
2 (* *)
3 (* The Why3 Verification Platform / The Why3 Development Team *)
4 (* Copyright 2010-2023 -- Inria - CNRS - Paris-Saclay University *)
5 (* *)
6 (* This software is distributed under the terms of the GNU Lesser *)
7 (* General Public License version 2.1, with the special exception *)
8 (* on linking described in file LICENSE. *)
9 (* *)
10 (********************************************************************)
12 open Format
13 open Why3
14 open Session_itp
15 open Why3session_lib
17 module Hprover = Whyconf.Hprover
19 let opt_style = ref 1
20 let opt_output_dir = ref ""
21 let opt_longtable = ref false
22 let opt_elements = ref None
24 let add_element s =
25 let l = match !opt_elements with
26 | None -> [s]
27 | Some r -> s :: r
29 opt_elements := Some l
31 let spec =
32 let open Getopt in
33 [ KLong "style", Hnd1 (AInt, fun i -> opt_style := i),
34 "<n> set output style (1 or 2, default 1)";
35 KShort 'o', Hnd1 (AString, fun s -> opt_output_dir := s),
36 "<dir> set output directory (default: session dir)";
37 KShort 'e', Hnd1 (AString, add_element),
38 "<path> produce a table for the given element";
39 KLong "longtable", Hnd0 (fun () -> opt_longtable := true),
40 " use 'longtable' environment instead of 'tabular'"
43 (* Statistics in LaTeX*)
46 let provers_latex_stats_goal provers goal =
47 goal_iter_proof_attempt (fun a ->
48 Hprover.replace provers a.S.proof_prover a.S.proof_prover) goal
50 let provers_latex_stats provers theory =
51 S.theory_iter_proof_attempt (fun a ->
52 Hprover.replace provers a.S.proof_prover a.S.proof_prover) theory
54 let provers_latex_stats_file provers file =
55 S.file_iter_proof_attempt (fun a ->
56 Hprover.replace provers a.S.proof_prover a.S.proof_prover) file
59 let protect s =
60 let b = Buffer.create 7 in
61 for i = 0 to String.length s - 1 do
62 match s.[i] with
63 '_' -> Buffer.add_string b "\\_"
64 | c -> Buffer.add_char b c
65 done;
66 Buffer.contents b
69 let column n depth provers =
70 if n == 1 then
71 if depth > 1 then
72 (List.length provers) + depth
73 else
74 (List.length provers) + depth + 1
75 else
76 (List.length provers) + 1
78 let print_head n depth provers fmt =
79 if n == 1 then
80 if (depth > 1) then
81 fprintf fmt "\\hline \\multicolumn{%d}{|c|}{Proof obligations } "
82 depth
83 else
84 fprintf fmt "\\hline \\multicolumn{%d}{|c|}{Proof obligations } "
85 (depth + 1)
86 else
87 fprintf fmt "\\hline Proof obligations ";
88 List.iter (fun a -> fprintf fmt "& \\provername{%a} " Whyconf.print_prover a)
89 provers;
90 fprintf fmt "\\\\ @."
92 let print_tabular_head n depth provers fmt =
93 pp_print_string fmt "\\begin{tabular}{|l|";
94 for _i = 0 to depth do pp_print_string fmt "l|" done;
95 for _i = 1 to (List.length provers) do pp_print_string fmt "c|" done;
96 fprintf fmt "}@.";
97 print_head n depth provers fmt
99 let print_tabular_foot fmt =
100 fprintf fmt "\\hline \\end{tabular}@."
103 let print_result_prov s proofs prov fmt=
104 List.iter (fun p ->
106 let pr = get_proof_attempt_node s (Hprover.find proofs p) in
107 let s = pr.proof_state in
108 match s with
109 | Some res ->
110 begin
111 match res.Call_provers.pr_answer with
112 | Call_provers.Valid ->
113 fprintf fmt "& \\valid{%.2f} " res.Call_provers.pr_time
114 | Call_provers.Invalid ->
115 fprintf fmt "& \\invalid{%.2f} " res.Call_provers.pr_time
116 | Call_provers.Timeout ->
117 fprintf fmt "& \\timeout{%.2fs} "
118 pr.limits.Call_provers.limit_time
119 | Call_provers.OutOfMemory ->
120 fprintf fmt "& \\outofmemory{%dM} "
121 pr.limits.Call_provers.limit_mem
122 | Call_provers.StepLimitExceeded ->
123 pp_print_string fmt "& \\steplimitexceeded "
124 | Call_provers.Unknown _ ->
125 fprintf fmt "& \\unknown{%.2f} " res.Call_provers.pr_time
126 | Call_provers.Failure _ ->
127 pp_print_string fmt "& \\failure "
128 | Call_provers.HighFailure _ ->
129 pp_print_string fmt "& \\highfailure "
132 | None -> pp_print_string fmt "(no result)"
133 with Not_found -> pp_print_string fmt "& \\noresult") prov;
134 fprintf fmt "\\\\ @."
137 let rec goal_latex_stat s fmt prov depth depth_max subgoal g =
138 let column = column 1 depth prov
140 if depth > 0 then
141 if subgoal > 0 then
142 fprintf fmt "\\cline{%d-%d}@." (depth + 1) column
143 else ()
144 else
145 fprintf fmt "\\hline@.";
146 if depth_max > 1 then
147 begin
148 if subgoal > 0 then
149 begin
150 if(depth < depth_max) then
151 for _i = 1 to depth do
152 pp_print_string fmt " & "
153 done
154 else
155 for _i = 1 to depth - 1 do
156 pp_print_string fmt " & "
157 done
159 else
160 if(depth < depth_max) then
161 if depth > 0 then
162 pp_print_string fmt " & "
164 else
165 begin
166 if subgoal > 0 then
167 for _i = 1 to depth do pp_print_string fmt " & " done
168 else
169 if depth > 0 then pp_print_string fmt " & "
170 end;
171 if (depth <= 1) then
172 fprintf fmt "\\explanation{%s} "
173 (protect (goal_full_name s g))
174 else
175 fprintf fmt " " ;
176 let proofs = get_proof_attempt_ids s g in
177 if (Hprover.length proofs) > 0 then
178 begin
179 if depth_max <= 1 then
180 begin
181 if depth > 0 then
182 for _i = depth to (depth_max - depth) do
183 fprintf fmt "& " done
184 else
185 for _i = depth to (depth_max - depth - 1) do
186 fprintf fmt "& " done
188 else
189 if depth > 0 then
190 for _i = depth to (depth_max - depth - 1) do
191 fprintf fmt "& " done
192 else
193 for _i = depth to (depth_max - depth - 2) do
194 fprintf fmt "& " done;
195 print_result_prov s proofs prov fmt;
196 end;
197 let tr = get_transformations s g in
198 if List.length tr > 0 then
199 if Hprover.length proofs > 0 then
200 fprintf fmt "\\cline{%d-%d}@." (depth + 2) column;
201 List.iter (fun tr ->
202 let goals = get_sub_tasks s tr in
203 let _ = List.fold_left (fun subgoal g ->
204 goal_latex_stat s fmt prov (depth + 1) depth_max (subgoal) g;
205 subgoal + 1) 0 goals in
206 () ) tr
209 let style_2_row fmt ?(transf=false) depth prov subgoal expl=
210 let column = column 2 depth prov in
211 if depth > 0 || transf then
212 fprintf fmt "\\cline{%d-%d}@." 2 column
213 else
214 fprintf fmt "\\hline@.";
215 for _i = 1 to depth do pp_print_string fmt "\\quad" done;
216 let macro = if transf then "transformation" else "explanation" in
217 if depth = 0 || transf then
218 fprintf fmt "\\%s{%s} " macro expl
219 else
220 fprintf fmt "\\subgoal{%s}{%d} " expl (subgoal + 1)
222 let rec goal_latex2_stat s fmt prov depth depth_max subgoal g =
223 let proofs = get_proof_attempt_ids s g in
224 if Hprover.length proofs > 0 then
225 begin
226 style_2_row fmt depth prov subgoal
227 (protect (goal_full_name s g));
228 print_result_prov s proofs prov fmt
230 else
231 if (*depth = 0*) true then
232 begin
233 style_2_row fmt depth prov subgoal
234 (protect (goal_full_name s g));
235 fprintf fmt "& \\multicolumn{%d}{|c|}{}\\\\ @."
236 (List.length prov)
237 end;
238 let tr = get_transformations s g in
239 if List.length tr > 0 then
240 begin
241 List.iter
242 (fun tr ->
243 let name = get_transf_string s tr in
244 style_2_row fmt ~transf:true (depth+1) prov subgoal
245 (protect name);
246 fprintf fmt "& \\multicolumn{%d}{|c|}{}\\\\@."
247 (List.length prov);
248 let goals = get_sub_tasks s tr in
249 let _ = List.fold_left
250 (fun subgoal g ->
251 goal_latex2_stat s fmt prov (depth + 1) depth_max (subgoal) g;
252 subgoal + 1) 0 goals in
253 () ) tr
255 else
256 if (Hprover.length proofs) == 0 && depth <> 0 then
257 fprintf fmt "\\\\@."
259 let latex_tabular_goal n s fmt depth provers g =
260 print_tabular_head n depth provers fmt;
261 if n == 1 then
262 goal_latex_stat s fmt provers 0 depth 0 g
263 else
264 goal_latex2_stat s fmt provers 0 depth 0 g;
265 print_tabular_foot fmt
267 let latex_tabular_aux n s fmt depth provers t =
268 if n == 1 then
269 List.iter (goal_latex_stat s fmt provers 0 depth 0) (theory_goals t)
270 else
271 List.iter (goal_latex2_stat s fmt provers 0 depth 0) (theory_goals t)
273 let latex_tabular n s fmt depth provers t =
274 print_tabular_head n depth provers fmt;
275 latex_tabular_aux n s fmt depth provers t;
276 print_tabular_foot fmt
279 let latex_tabular_file n s fmt depth provers f =
280 print_tabular_head n depth provers fmt;
281 List.iter (latex_tabular_aux n s fmt depth provers) (file_theories f);
282 print_tabular_foot fmt
285 let latex_longtable n s fmt depth name provers t=
286 pp_print_string fmt "\\begin{longtable}{| l |";
287 for _i = 0 to (List.length provers) + depth do pp_print_string fmt "c |" done;
288 fprintf fmt "}@.";
289 (* First head *)
290 print_head n depth provers fmt;
291 fprintf fmt "\\hline \\endfirsthead @.";
292 (* Other heads : "Continued... " added *)
293 fprintf fmt "\\multicolumn{%d}{r}{\\textit{Continued from previous page}} \
294 \\\\ @." (List.length provers + 1) ;
295 fprintf fmt "\\hline @.";
296 print_head n depth provers fmt;
297 fprintf fmt "\\hline \\endhead @.";
298 (* Other foots : "Continued..." added *)
299 fprintf fmt "\\hline \\multicolumn{%d}{r}{\\textit{Continued on next page}} \
300 \\\\ @." (List.length provers);
301 (* Last foot : nothing *)
302 fprintf fmt "\\endfoot \\endlastfoot @.";
303 if n == 1 then
304 List.iter (goal_latex_stat s fmt provers 0 depth 0) (theory_goals t)
305 else
306 List.iter (goal_latex2_stat s fmt provers 0 depth 0) (theory_goals t);
307 fprintf fmt "\\hline \\caption{%s statistics} @." (protect name);
308 fprintf fmt "\\label{%s} \\end{longtable}@." (protect name)
311 let theory_latex_stat n s table dir t =
312 let provers = get_used_provers_theory s t in
313 let provers = Whyconf.Sprover.fold (fun pr acc -> pr :: acc)
314 provers [] in
315 let provers = List.sort Whyconf.Prover.compare provers in
316 let depth = theory_depth s t in
317 let name = (theory_name t).Ident.id_string in
318 let ch = open_out (Filename.concat dir(name^".tex")) in
319 let fmt = formatter_of_out_channel ch in
320 if table = "tabular" then
321 begin
322 latex_tabular n s fmt depth provers t
324 else
325 latex_longtable n s fmt depth name provers t;
326 close_out ch
328 let file_latex_stat n s table dir f =
329 List.iter (theory_latex_stat n s table dir) (file_theories f)
331 let standalone_goal_latex_stat n s _table dir g =
332 let provers = get_used_provers_goal s g in
333 let provers = Whyconf.Sprover.fold (fun pr acc -> pr :: acc)
334 provers [] in
335 let provers = List.sort Whyconf.Prover.compare provers in
336 let depth = goal_depth s g in
337 let name = (get_proof_name s g).Ident.id_string in
338 let ch = open_out (Filename.concat dir (name^".tex")) in
339 let fmt = formatter_of_out_channel ch in
340 latex_tabular_goal n s fmt depth provers g;
342 if table = "tabular" then
343 begin
344 latex_tabular_goal n fmt depth provers g
346 else
347 latex_longtable_goal n fmt depth name provers g;
349 close_out ch
351 let file_latex_stat_all n s _table dir f =
352 let provers = get_used_provers_file s f in
353 let provers = Whyconf.Sprover.fold (fun pr acc -> pr :: acc)
354 provers [] in
355 let provers = List.sort Whyconf.Prover.compare provers in
356 let depth = file_depth s f in
357 let name = Sysutil.basename (file_path f) in
358 let ch = open_out (Filename.concat dir (name ^ ".tex")) in
359 let fmt = formatter_of_out_channel ch in
360 latex_tabular_file n s fmt depth provers f;
362 if table = "tabular" then
363 begin
364 latex_tabular n fmt depth provers t
366 else
367 latex_longtable n fmt depth name provers t;
370 close_out ch
374 let element_latex_stat_goal g n s table dir r =
375 begin
376 match r with
377 | [] -> ()
378 | _ ->
379 eprintf "Warning: only main goals are supported@.:"
380 end;
381 standalone_goal_latex_stat n s table dir g
383 let element_latex_stat_theory s th n table dir e =
384 match e with
385 | [] -> theory_latex_stat n s table dir th
386 | g :: r ->
388 let goals =
389 List.map (fun g ->
390 (get_proof_name s g).Ident.id_string,g)
391 (theory_goals th)
393 let g = List.assoc g goals in
394 element_latex_stat_goal g n s table dir r
395 with Not_found ->
396 eprintf "Warning: goal not found in path: %s@." g
398 let element_latex_stat_file f n s table dir e =
399 match e with
400 | [] -> file_latex_stat_all n s table dir f
401 | th :: r ->
403 let ths =
404 List.map (fun th -> (theory_name th).Ident.id_string,th)
405 (file_theories f)
407 let th = List.assoc th ths in
408 element_latex_stat_theory s th n table dir r
409 with Not_found ->
410 eprintf "Warning: theory not found in path: %s@." th
413 let element_latex_stat files n s table dir e =
414 eprintf "Element %s@." e;
415 match Strings.split '.' e with
416 | [] -> ()
417 | f :: r ->
418 let found = ref false in
419 Hfile.iter
420 (fun _ file ->
421 let fname = Sysutil.basename (file_path file) in
422 let fname = List.hd (Strings.split '.' fname) in
423 if fname = f then
424 begin
425 found := true;
426 element_latex_stat_file file n s table dir r
427 end)
428 files;
429 if not !found then
430 eprintf "Warning: file not found for element %s@." e
432 let print_latex_statistics n table dir session =
433 let files = get_files session in
434 match !opt_elements with
435 | None ->
436 Hfile.iter (fun _ f -> file_latex_stat n session table dir f) files
437 | Some l ->
438 List.iter (element_latex_stat files n session table dir) l
442 let table () = if !opt_longtable then "longtable" else "tabular"
444 let run_one fname =
445 let ses = read_session fname in
446 let project_dir = get_dir ses in
447 let dir = if !opt_output_dir = "" then project_dir else
448 !opt_output_dir
450 print_latex_statistics !opt_style (table ()) dir ses
452 let run () =
453 let _,_ = Whyconf.Args.complete_initialization () in
454 iter_session_files run_one
457 let cmd =
458 { cmd_spec = spec;
459 cmd_desc = "output session in LaTeX format";
460 cmd_usage = "<session>\nOutput session in LaTeX format.";
461 cmd_name = "latex";
462 cmd_run = run;