From f054eea1063124c252ad88ab23f2e468aa72bed8 Mon Sep 17 00:00:00 2001 From: Michele Alberti <michele.alberti@cea.fr> Date: Tue, 14 Feb 2023 12:19:57 +0100 Subject: [PATCH] [verification] Rework additional information for dataset results and simplify its JSON serialization. --- src/JSON.ml | 2 +- src/JSON.mli | 2 +- src/main.ml | 52 ++++++++++++++++++-------------------------- src/verification.ml | 43 +++++++++++------------------------- src/verification.mli | 9 ++++---- 5 files changed, 41 insertions(+), 67 deletions(-) diff --git a/src/JSON.ml b/src/JSON.ml index 502f4be..9ed36e5 100644 --- a/src/JSON.ml +++ b/src/JSON.ml @@ -43,7 +43,7 @@ type output = { id : string; prover_answer : prover_answer; percentage_valid : float; - dataset_results : string; + dataset_results : prover_answer list; } and prover_answer = Call_provers.prover_answer = diff --git a/src/JSON.mli b/src/JSON.mli index 96a7b6c..550cb40 100644 --- a/src/JSON.mli +++ b/src/JSON.mli @@ -42,7 +42,7 @@ type output = { id : string; prover_answer : prover_answer; percentage_valid : float; - dataset_results : string; + dataset_results : prover_answer list; } and prover_answer = Call_provers.prover_answer = diff --git a/src/main.ml b/src/main.ml index d7d68f1..00b42e0 100644 --- a/src/main.ml +++ b/src/main.ml @@ -149,40 +149,30 @@ let verify ?format ~loadpath ?memlimit ?timelimit ?dataset prover ?prover_altern List.iter theory_answers ~f:log_theory_answer; theory_answers -let record_dataset_results id prover_answer dataset outfile = +let record_json_output id prover_answer dataset_results file = let percentage_valid = let nb_valid = - List.count dataset ~f:(fun record -> - match List.hd_exn record with "Valid" -> true | _ -> false) + List.count dataset_results ~f:(fun prover_answer -> + match prover_answer with Why3.Call_provers.Valid -> true | _ -> false) in let nb_valid = Float.of_int nb_valid in - let total = Float.of_int (List.length dataset) in + let total = Float.of_int (List.length dataset_results) in nb_valid /. total *. 100. in - let dataset_results = - let dataset_results, csv_out_channel = - let filename, out_channel = - Caml.Filename.open_temp_file "caisar" "results.csv" - in - (filename, Csv.to_channel out_channel) - in - Csv.output_all csv_out_channel dataset; - Csv.close_out csv_out_channel; - dataset_results - in let output = { JSON.id; prover_answer; percentage_valid; dataset_results } in - let out_channel = Stdlib.open_out outfile in + let out_channel = Stdlib.open_out file in Yojson.Safe.to_channel out_channel (JSON.output_to_yojson output); - Logs.info (fun m -> m "@[Results recorded in file '%s'@]" outfile); + Logs.info (fun m -> m "@[Results recorded in file '%s'@]" file); Stdlib.close_out out_channel -let record_theory_answers id outfile = - Why3.Wstdlib.Mstr.iter (fun theory_name task_answers -> - match task_answers with - | [ { Verification.prover_answer; additional_info = Dataset dataset; _ } ] - -> - record_dataset_results id prover_answer dataset outfile - | _ -> failwith (Fmt.str "Unexpected answers for theory '%s'" theory_name)) +let record_verification_result id verification_result file = + Why3.Wstdlib.Mstr.iter + (fun name (answers : Verification.answer list) -> + match answers with + | [ { prover_answer; additional_info = Dataset dataset_results; _ } ] -> + record_json_output id prover_answer dataset_results file + | _ -> failwith (Fmt.str "Unexpected answers for theory '%s'" name)) + verification_result let verify_json ?memlimit ?timelimit ?outfile json = let jin = JSON.input_of_string json in @@ -202,16 +192,16 @@ let verify_json ?memlimit ?timelimit ?outfile json = (* Precedence to the command line option, if any. *) match outfile with Some _ -> outfile | None -> jin.output_file in - let file = Result.ok_or_failwith (Verification.File.of_json_input jin) in - let theory_answers = + let infile = Result.ok_or_failwith (Verification.File.of_json_input jin) in + let verification_results = verify ~loadpath:[] ?memlimit ?timelimit ~dataset:jin.property.dataset - jin.prover [ file ] + jin.prover [ infile ] in - match theory_answers with + match verification_results with | [] -> assert false (* We always build one theory from the provided JSON. *) - | [ theory_answer ] -> - Option.iter outfile ~f:(fun outfile -> - record_theory_answers jin.id outfile theory_answer) + | [ verification_result ] -> + Option.iter outfile + ~f:(record_verification_result jin.id verification_result) | _ -> failwith "Unexpected more than one theory from a JSON file" let exec_cmd cmdname cmd = diff --git a/src/verification.ml b/src/verification.ml index b606275..1f9a37d 100644 --- a/src/verification.ml +++ b/src/verification.ml @@ -57,7 +57,7 @@ module File = struct | JSON jin -> JSON.pretty_input fmt jin end -type theory_answer = answer list Wstdlib.Mstr.t +type verification_result = answer list Wstdlib.Mstr.t and answer = { id : Decl.prsymbol; @@ -67,7 +67,7 @@ and answer = { and additional_info = | Generic of string option - | Dataset of Csv.t + | Dataset of Call_provers.prover_answer list let () = Language.register_nnet_support (); @@ -116,12 +116,12 @@ let answer_saver limit config env config_prover dataset task = match answer.prover_answer with | Call_provers.Unknown "" -> let additional_info = Fmt.str "%d/%d" answer.nb_proved answer.nb_total in - (Call_provers.Unknown additional_info, None) + (Call_provers.Unknown additional_info, Generic None) | Call_provers.Unknown _ -> assert false (* By construction of SAVer's Unknown answer. *) | prover_answer -> let additional_info = Fmt.str "(%d/%d)" answer.nb_proved answer.nb_total in - (prover_answer, Some additional_info) + (prover_answer, Generic (Some additional_info)) let answer_aimos limit config env config_prover dataset task aimos_config = let predicate = @@ -156,7 +156,7 @@ let answer_aimos limit config env config_prover dataset task aimos_config = let answer = AIMOS.call_prover limit config config_prover predicate aimos_filename in - let additional_info = None in + let additional_info = Generic None in (answer, additional_info) let nnet_or_onnx = Re__Core.(compile (str "%{nnet-onnx}")) @@ -230,12 +230,7 @@ let answer_dataset limit config env prover config_prover driver dataset task = Csv.close_in csv_in_channel; if List.length dataset <> List.length dataset_answers then failwith "Inconsistent number of prover answers and dataset records" - else - List.map2_exn dataset dataset_answers ~f:(fun record prover_answer -> - let result = - Fmt.str "%a" Call_provers.print_prover_answer prover_answer - in - result :: record) + else Dataset dataset_answers in (prover_answer, additional_info) @@ -261,33 +256,21 @@ let answer_generic limit config env prover config_prover driver task = List.map tasks ~f:(call_prover_on_task limit config command driver) in let prover_answer = combine_prover_answers answers in - (prover_answer, None) + let additional_info = Generic None in + (prover_answer, additional_info) let call_prover ?dataset ~limit config env prover config_prover driver task = let prover_answer, additional_info = match prover with - | Prover.Saver -> - let prover_answer, additional_info = - answer_saver limit config env config_prover dataset task - in - (prover_answer, Generic additional_info) + | Prover.Saver -> answer_saver limit config env config_prover dataset task | Aimos -> - let prover_answer, additional_info = - (* TODO: add real config file *) - answer_aimos limit config env config_prover dataset task None - in - (prover_answer, Generic additional_info) + (* TODO: add real config file *) + answer_aimos limit config env config_prover dataset task None | (Marabou | Pyrat | Nnenum) when Option.is_some dataset -> let dataset = Unix.realpath (Option.value_exn dataset) in - let prover_answer, additional_info = - answer_dataset limit config env prover config_prover driver dataset task - in - (prover_answer, Dataset additional_info) + answer_dataset limit config env prover config_prover driver dataset task | Marabou | Pyrat | CVC5 | Nnenum -> - let prover_answer, additional_info = - answer_generic limit config env prover config_prover driver task - in - (prover_answer, Generic additional_info) + answer_generic limit config env prover config_prover driver task in let id = Task.task_goal task in { id; prover_answer; additional_info } diff --git a/src/verification.mli b/src/verification.mli index 1c93426..8dc3939 100644 --- a/src/verification.mli +++ b/src/verification.mli @@ -30,7 +30,7 @@ module File : sig val pretty : Format.formatter -> t -> unit end -type theory_answer = answer list Wstdlib.Mstr.t +type verification_result = answer list Wstdlib.Mstr.t and answer = private { id : Decl.prsymbol; @@ -40,7 +40,8 @@ and answer = private { and additional_info = private | Generic of string option - | Dataset of Csv.t + | Dataset of Call_provers.prover_answer list + (** A prover answer per data point. *) val verify : ?debug:bool -> @@ -52,8 +53,8 @@ val verify : Prover.t -> ?prover_altern:string -> File.t -> - theory_answer -(** [verify debug format loadpath memlimit timelimit dataset prover prover_altern file] + verification_result +(** [verify ?debug ?format ~loadpath ?memlimit ?timelimit ?dataset prover ?prover_altern file] launches a verification of the given [file] with the provided [prover] and [dataset]. -- GitLab