sidekick/src/simplify/sidekick_simplify.ml

81 lines
2.4 KiB
OCaml

open Sidekick_core
type t = {
tst: Term.store;
proof: Sidekick_proof.Tracer.t;
mutable hooks: hook list;
(* store [t --> u by step_ids] in the cache.
We use a bag for the proof steps because it gives us structural
sharing of subproofs. *)
cache: (Term.t * Sidekick_proof.Step.id Bag.t) Term.Tbl.t;
}
and hook = t -> Term.t -> (Term.t * Sidekick_proof.Step.id Iter.t) option
let create tst ~proof : t =
let proof = (proof : #Sidekick_proof.Tracer.t :> Sidekick_proof.Tracer.t) in
{ tst; proof; hooks = []; cache = Term.Tbl.create 32 }
let[@inline] tst self = self.tst
let[@inline] proof self = self.proof
let add_hook self f = self.hooks <- f :: self.hooks
let clear self = Term.Tbl.clear self.cache
let normalize (self : t) (t : Term.t) : (Term.t * Sidekick_proof.Step.id) option
=
(* compute and cache normal form of [t] *)
let rec loop t : Term.t * _ Bag.t =
match Term.Tbl.find self.cache t with
| res -> res
| exception Not_found ->
if Term.is_a_type t then
t, Bag.empty
else (
let steps_u = ref Bag.empty in
let u = aux_rec ~steps:steps_u t self.hooks in
Term.Tbl.add self.cache t (u, !steps_u);
u, !steps_u
)
and loop_add ~steps t =
let u, pr_u = loop t in
steps := Bag.append !steps pr_u;
u
(* try each function in [hooks] successively, and rewrite subterms *)
and aux_rec ~steps t hooks : Term.t =
match hooks with
| [] ->
let u =
Term.map_shallow self.tst t ~f:(fun _inb sub_t -> loop_add ~steps sub_t)
in
if Term.equal t u then
t
else
loop_add ~steps u
| h :: hooks_tl ->
(match h self t with
| None -> aux_rec ~steps t hooks_tl
| Some (u, _) when Term.equal t u -> aux_rec ~steps t hooks_tl
| Some (u, pr_u) ->
let bag_u = Bag.of_iter pr_u in
steps := Bag.append !steps bag_u;
let v, pr_v = loop u in
(* fixpoint *)
steps := Bag.append !steps pr_v;
v)
in
let u, pr_u = loop t in
if Term.equal t u then
None
else (
(* proof: [sub_proofs |- t=u] by CC + subproof *)
let step =
Sidekick_proof.Tracer.add_step self.proof @@ fun () ->
Sidekick_proof.Core_rules.lemma_preprocess t u ~using:(Bag.to_list pr_u)
in
Some (u, step)
)
let normalize_t self t =
match normalize self t with
| Some (u, pr_u) -> u, Some pr_u
| None -> t, None