1 (********************************************************************)
3 (* The Why3 Verification Platform / The Why3 Development Team *)
4 (* Copyright 2010-2023 -- Inria - CNRS - Paris-Saclay University *)
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. *)
10 (********************************************************************)
17 module Hprover
= Whyconf.Hprover
20 let opt_output_dir = ref ""
21 let opt_longtable = ref false
22 let opt_elements = ref None
25 let l = match !opt_elements with
29 opt_elements := Some
l
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
60 let b = Buffer.create
7 in
61 for i
= 0 to String.length s
- 1 do
63 '_'
-> Buffer.add_string
b "\\_"
64 | c
-> Buffer.add_char
b c
69 let column n depth provers
=
72 (List.length provers
) + depth
74 (List.length provers
) + depth
+ 1
76 (List.length provers
) + 1
78 let print_head n depth provers fmt
=
81 fprintf fmt
"\\hline \\multicolumn{%d}{|c|}{Proof obligations } "
84 fprintf fmt
"\\hline \\multicolumn{%d}{|c|}{Proof obligations } "
87 fprintf fmt
"\\hline Proof obligations ";
88 List.iter
(fun a
-> fprintf fmt
"& \\provername{%a} " Whyconf.print_prover a
)
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;
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
=
106 let pr = get_proof_attempt_node s
(Hprover.find proofs p
) in
107 let s = pr.proof_state
in
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
142 fprintf fmt
"\\cline{%d-%d}@." (depth
+ 1) column
145 fprintf fmt
"\\hline@.";
146 if depth_max
> 1 then
150 if(depth
< depth_max
) then
151 for _i
= 1 to depth
do
152 pp_print_string fmt
" & "
155 for _i
= 1 to depth
- 1 do
156 pp_print_string fmt
" & "
160 if(depth
< depth_max
) then
162 pp_print_string fmt
" & "
167 for _i
= 1 to depth
do pp_print_string fmt
" & " done
169 if depth
> 0 then pp_print_string fmt
" & "
172 fprintf fmt
"\\explanation{%s} "
173 (protect (goal_full_name
s g
))
176 let proofs = get_proof_attempt_ids
s g
in
177 if (Hprover.length
proofs) > 0 then
179 if depth_max
<= 1 then
182 for _i
= depth
to (depth_max
- depth
) do
183 fprintf fmt
"& " done
185 for _i
= depth
to (depth_max
- depth
- 1) do
186 fprintf fmt
"& " done
190 for _i
= depth
to (depth_max
- depth
- 1) do
191 fprintf fmt
"& " done
193 for _i
= depth
to (depth_max
- depth
- 2) do
194 fprintf fmt
"& " done;
195 print_result_prov s proofs prov fmt
;
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;
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
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
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
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
226 style_2_row fmt depth prov subgoal
227 (protect (goal_full_name
s g
));
228 print_result_prov s proofs prov fmt
231 if (*depth = 0*) true then
233 style_2_row fmt depth prov subgoal
234 (protect (goal_full_name
s g
));
235 fprintf fmt
"& \\multicolumn{%d}{|c|}{}\\\\ @."
238 let tr = get_transformations
s g
in
239 if List.length
tr > 0 then
243 let name = get_transf_string
s tr in
244 style_2_row fmt ~transf
:true (depth
+1) prov subgoal
246 fprintf fmt
"& \\multicolumn{%d}{|c|}{}\\\\@."
248 let goals = get_sub_tasks
s tr in
249 let _ = List.fold_left
251 goal_latex2_stat s fmt prov
(depth
+ 1) depth_max
(subgoal
) g
;
252 subgoal
+ 1) 0 goals in
256 if (Hprover.length
proofs) == 0 && depth
<> 0 then
259 let latex_tabular_goal n
s fmt depth provers g
=
260 print_tabular_head n depth provers fmt
;
262 goal_latex_stat s fmt provers
0 depth
0 g
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
=
269 List.iter
(goal_latex_stat s fmt provers
0 depth
0) (theory_goals t
)
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;
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 @.";
304 List.iter
(goal_latex_stat s fmt provers
0 depth
0) (theory_goals t
)
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
)
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
322 latex_tabular n
s fmt depth provers t
325 latex_longtable n
s fmt depth name provers t
;
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
)
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
344 latex_tabular_goal n fmt depth provers g
347 latex_longtable_goal n fmt depth name provers g;
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
)
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
364 latex_tabular n fmt depth provers t
367 latex_longtable n fmt depth name provers t;
374 let element_latex_stat_goal g n
s table dir r
=
379 eprintf
"Warning: only main goals are supported@.:"
381 standalone_goal_latex_stat n
s table dir g
383 let element_latex_stat_theory s th n table dir e
=
385 | [] -> theory_latex_stat n
s table dir th
390 (get_proof_name
s g
).Ident.id_string
,g
)
393 let g = List.assoc
g goals in
394 element_latex_stat_goal g n
s table dir r
396 eprintf
"Warning: goal not found in path: %s@." g
398 let element_latex_stat_file f n
s table dir e
=
400 | [] -> file_latex_stat_all n
s table dir f
404 List.map
(fun th
-> (theory_name th
).Ident.id_string
,th
)
407 let th = List.assoc
th ths in
408 element_latex_stat_theory s th n table dir r
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
418 let found = ref false in
421 let fname = Sysutil.basename
(file_path file
) in
422 let fname = List.hd
(Strings.split '
.'
fname) in
426 element_latex_stat_file file n
s table dir r
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
436 Hfile.iter
(fun _ f
-> file_latex_stat n session table dir f
) files
438 List.iter
(element_latex_stat files n session table dir
) l
442 let table () = if !opt_longtable then "longtable" else "tabular"
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
450 print_latex_statistics !opt_style (table ()) dir ses
453 let _,_ = Whyconf.Args.complete_initialization
() in
454 iter_session_files
run_one
459 cmd_desc
= "output session in LaTeX format";
460 cmd_usage
= "<session>\nOutput session in LaTeX format.";