sidekick/src/base/Proof_quip.ml.tmp
2022-08-05 21:56:17 -04:00

330 lines
10 KiB
Text

(* output proof *)
module P = Sidekick_quip.Proof
(* serialized proof trace *)
module PS = Sidekick_base_proof_trace.Proof_ser
type t = P.t
module type CONV_ARG = sig
val proof : Proof.t
val unsat : Proof.step_id
end
module Make_lazy_tbl (T : sig
type t
end)
() =
struct
let lazy_tbl_ : T.t lazy_t Util.Int_tbl.t = Util.Int_tbl.create 32
(** FInd step by its ID *)
let find (id : PS.ID.t) : T.t =
match Util.Int_tbl.get lazy_tbl_ (Int32.to_int id) with
| Some (lazy p) -> p
| None ->
Error.errorf "proof-quip: step `%a` was not reconstructed" PS.ID.pp id
(** Add entry *)
let add id (e : T.t lazy_t) =
assert (not (Util.Int_tbl.mem lazy_tbl_ (Int32.to_int id)));
Util.Int_tbl.add lazy_tbl_ (Int32.to_int id) e
end
module Conv (X : CONV_ARG) : sig
val reconstruct : unit -> t
end = struct
let ( !! ) = Lazy.force
(* Steps we need to decode.
Invariant: the IDs of these steps must be lower than the current processed
ID (we start from the end) *)
let needed_steps_ = Util.Int_tbl.create 128
let add_needed_step (id : PS.ID.t) : unit =
Util.Int_tbl.replace needed_steps_ (Int32.to_int id) ()
let unsat_id = Proof.Unsafe_.id_of_proof_step_ X.unsat
(* start with the unsat step *)
let () = add_needed_step unsat_id
(* store reconstructed proofs, but lazily because their dependencies
(sub-steps, terms, etc.) might not have come up in the reverse stream yet. *)
module L_proofs =
Make_lazy_tbl
(struct
type t = P.t
end)
()
(* store reconstructed terms *)
module L_terms =
Make_lazy_tbl
(struct
type t = P.term
end)
()
(* id -> function symbol *)
let funs : P.Fun.t Util.Int_tbl.t = Util.Int_tbl.create 32
let find_fun (f : PS.ID.t) : P.Fun.t =
try Util.Int_tbl.find funs (Int32.to_int f)
with Not_found -> Error.errorf "unknown function '%ld'" f
(* list of toplevel steps, in the final proof order *)
let top_steps_ : P.composite_step lazy_t list ref = ref []
let add_top_step s = top_steps_ := s :: !top_steps_
let conv_lit (lit : PS.Lit.t) : P.Lit.t lazy_t =
let v = Int32.abs lit in
add_needed_step v;
lazy
(let t = L_terms.find v in
let sign = lit > Int32.zero in
(* reconstruct literal *)
P.Lit.mk sign t)
let conv_lits (lits : PS.Lit.t array) : P.Lit.t list lazy_t =
let lits = lits |> Util.array_to_list_map conv_lit in
lazy (List.map Lazy.force lits)
let conv_clause (c : PS.Clause.t) : P.clause lazy_t = conv_lits c.lits
let name_clause (id : PS.ID.t) : string = Printf.sprintf "c%ld" id
let name_step (id : PS.ID.t) : string = Printf.sprintf "s%ld" id
let name_term (id : PS.ID.t) : string = Printf.sprintf "t%ld" id
(* TODO: see if we can allow `(stepc c5 (cl …) (… (@ c5) …))`.
Namely, the alias `c5 := (cl …)` could be available within its own proof
so we don't have to print it twice, which is useful for rules like `ccl`
where it's typically `(stepc c5 (cl …) (ccl (cl …)))` for twice the space.
*)
let is_def_ (step : PS.Step.t) =
match step.view with
| PS.Step_view.Expr_def _ -> true
| _ -> false
(* process a step of the trace *)
let process_step_ (step : PS.Step.t) : unit =
let lid = step.id in
let id = Int32.to_int lid in
if Util.Int_tbl.mem needed_steps_ id || is_def_ step then (
Log.debugf 20 (fun k ->
k "(@[proof-quip.process-needed-step@ %a@])" PS.Step.pp step);
Util.Int_tbl.remove needed_steps_ id;
(* now process the step *)
match step.view with
| PS.Step_view.Step_input i ->
let c = conv_clause i.PS.Step_input.c in
let name = name_clause lid in
let step =
lazy (P.S_step_c { name; res = !!c; proof = P.assertion_c_l !!c })
in
add_top_step step;
(* refer to the step by name now *)
L_proofs.add lid (lazy (P.ref_by_name name))
| PS.Step_view.Step_unsat { c = uclause } ->
let c = [] in
let name = "unsat" in
add_needed_step uclause;
let name_c = name_clause uclause in
add_top_step
(lazy (P.S_step_c { name; res = c; proof = P.ref_by_name name_c }))
| PS.Step_view.Step_cc { eqns } ->
let c = conv_lits eqns in
let name = name_clause lid in
let step =
lazy (P.S_step_c { name; res = !!c; proof = P.cc_lemma !!c })
in
add_top_step step;
L_proofs.add lid (lazy (P.ref_by_name name))
| PS.Step_view.Fun_decl { f } -> Util.Int_tbl.add funs id f
| PS.Step_view.Expr_eq { lhs; rhs } ->
add_needed_step lhs;
add_needed_step rhs;
let name = name_term lid in
let step =
lazy
(let lhs = L_terms.find lhs and rhs = L_terms.find rhs in
let t = P.T.eq lhs rhs in
P.S_define_t_name (name, t))
in
add_top_step step;
L_terms.add lid (lazy (P.T.ref name))
| PS.Step_view.Expr_bool { b } ->
let t = Lazy.from_val (P.T.bool b) in
L_terms.add lid t
| PS.Step_view.Expr_isa { c; arg } ->
add_needed_step c;
add_needed_step arg;
let t =
lazy
(let c = find_fun c in
let arg = L_terms.find arg in
P.T.is_a c arg)
in
L_terms.add lid t
| PS.Step_view.Expr_app { f; args } ->
add_needed_step f;
Array.iter add_needed_step args;
let t =
lazy
(let f = find_fun f in
let args = Array.map L_terms.find args in
P.T.app_fun f args)
in
if Array.length args > 0 then (
(* introduce a name *)
let name = name_term lid in
let step = lazy (P.S_define_t_name (name, !!t)) in
add_top_step step;
L_terms.add lid (lazy (P.T.ref name))
) else
L_terms.add lid t
| PS.Step_view.Expr_def { c; rhs } ->
add_needed_step c;
add_needed_step rhs;
let name = name_clause lid in
(* add [name := (|- c=rhs) by refl c].
Make sure we do it first, order in final proof will be reversed. *)
let step_refl =
lazy
(let c = L_terms.find c in
let rhs = L_terms.find rhs in
P.S_step_c { name; res = [ P.Lit.eq c rhs ]; proof = P.refl c })
in
add_top_step step_refl;
(* define [c:=rhs] *)
let step_def =
lazy
(let c = L_terms.find c in
let rhs = L_terms.find rhs in
P.S_define_t (c, rhs))
in
add_top_step step_def;
L_proofs.add lid (lazy (P.ref_by_name name))
| PS.Step_view.Expr_not { f } ->
add_needed_step f;
let t =
lazy
(let f = L_terms.find f in
P.T.not_ f)
in
L_terms.add lid t
| PS.Step_view.Expr_if _ -> () (* TODO *)
| PS.Step_view.Step_rup { res; hyps } ->
let res = conv_clause res in
Array.iter add_needed_step hyps;
let name = name_clause lid in
let step =
lazy
(let hyps = Util.array_to_list_map L_proofs.find hyps in
P.S_step_c { name; res = !!res; proof = P.rup !!res hyps })
in
add_top_step step;
L_proofs.add lid (lazy (P.ref_by_name name))
| PS.Step_view.Step_clause_rw { c; res; using } ->
let res = conv_clause res in
add_needed_step c;
Array.iter add_needed_step using;
let name = name_clause lid in
let step =
lazy
(let c = L_proofs.find c in
let using = Util.array_to_list_map L_proofs.find using in
let res = !!res in
P.S_step_c
{ name; res; proof = P.Clause_rw { res; c0 = c; using } })
in
add_top_step step;
L_proofs.add lid (lazy (P.ref_by_name name))
| PS.Step_view.Step_proof_p1 { rw_with; c } ->
add_needed_step c;
add_needed_step rw_with;
let p =
lazy
(let rw_with = L_proofs.find rw_with in
let c = L_proofs.find c in
P.paramod1 rw_with c)
in
L_proofs.add lid p
| PS.Step_view.Step_proof_r1 { unit; c } ->
add_needed_step c;
add_needed_step unit;
let p =
lazy
(let unit = L_proofs.find unit in
let c = L_proofs.find c in
P.res1 unit c)
in
L_proofs.add lid p
| PS.Step_view.Step_proof_res { pivot; c1; c2 } ->
add_needed_step c1;
add_needed_step c2;
add_needed_step pivot;
let p =
lazy
(let pivot = L_terms.find pivot in
let c1 = L_proofs.find c2 in
let c2 = L_proofs.find c2 in
P.res ~pivot c1 c2)
in
L_proofs.add lid p
| PS.Step_view.Step_bool_c { rule; exprs } ->
let name = name_step lid in
Array.iter add_needed_step exprs;
let step =
lazy
(let exprs = Util.array_to_list_map L_terms.find exprs in
P.step_anon ~name @@ P.bool_c rule exprs)
in
add_top_step step;
L_proofs.add lid (lazy (P.ref_by_name name))
| PS.Step_view.Step_preprocess { t; u; using } ->
let name = name_clause lid in
add_needed_step t;
add_needed_step u;
Array.iter add_needed_step using;
let step =
lazy
(let t = L_terms.find t and u = L_terms.find u in
let using = Util.array_to_list_map L_proofs.find using in
let res = [ P.Lit.eq t u ] in
P.S_step_c { res; name; proof = P.cc_imply_l using t u })
in
add_top_step step;
L_proofs.add lid (lazy (P.ref_by_name name))
| PS.Step_view.Step_bridge_lit_expr _ -> assert false
| PS.Step_view.Step_bool_tauto _ -> () (* TODO *)
| PS.Step_view.Step_true _ -> ()
(* TODO *)
)
let reconstruct_once_ =
lazy
( Profile.with_ "proof-quip.reconstruct" @@ fun () ->
Proof.iter_steps_backward X.proof process_step_;
() )
let reconstruct () : t =
Lazy.force reconstruct_once_;
let steps = Util.array_of_list_map Lazy.force !top_steps_ in
P.composite_a steps
end
let of_proof (self : Proof.t) ~(unsat : Proof.step_id) : P.t =
let module C = Conv (struct
let proof = self
let unsat = unsat
end) in
C.reconstruct ()
type out_format = Sidekick_quip.out_format = Sexp | CSexp
let output = Sidekick_quip.output