mirror of
https://github.com/c-cube/sidekick.git
synced 2025-12-11 05:28:34 -05:00
feat(simplify): add sidekick_simplify library
This commit is contained in:
parent
83e456ef8a
commit
1e1b0f352d
3 changed files with 125 additions and 0 deletions
6
src/simplify/dune
Normal file
6
src/simplify/dune
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
(library
|
||||||
|
(name Sidekick_simplify)
|
||||||
|
(public_name sidekick.simplify)
|
||||||
|
(synopsis "Simplifier")
|
||||||
|
(libraries containers iter sidekick.core sidekick.util)
|
||||||
|
(flags :standard -w +32 -open Sidekick_util))
|
||||||
80
src/simplify/sidekick_simplify.ml
Normal file
80
src/simplify/sidekick_simplify.ml
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
open Sidekick_core
|
||||||
|
|
||||||
|
open struct
|
||||||
|
module P = Proof_trace
|
||||||
|
module Rule_ = Proof_core
|
||||||
|
end
|
||||||
|
|
||||||
|
type t = {
|
||||||
|
tst: Term.store;
|
||||||
|
proof: Proof_trace.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 * Proof_step.id Bag.t) Term.Tbl.t;
|
||||||
|
}
|
||||||
|
|
||||||
|
and hook = t -> Term.t -> (Term.t * Proof_step.id Iter.t) option
|
||||||
|
|
||||||
|
let create tst ~proof : t =
|
||||||
|
{ 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 * 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 ->
|
||||||
|
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 ~f:(fun _inb u -> loop_add ~steps u) 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 =
|
||||||
|
P.add_step self.proof
|
||||||
|
@@ Rule_.lemma_preprocess t u ~using:(Bag.to_iter 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
|
||||||
39
src/simplify/sidekick_simplify.mli
Normal file
39
src/simplify/sidekick_simplify.mli
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
(** Term simplifier *)
|
||||||
|
|
||||||
|
open Sidekick_core
|
||||||
|
|
||||||
|
type t
|
||||||
|
|
||||||
|
val tst : t -> Term.store
|
||||||
|
|
||||||
|
val create : Term.store -> proof:Proof_trace.t -> t
|
||||||
|
(** Create a simplifier *)
|
||||||
|
|
||||||
|
val clear : t -> unit
|
||||||
|
(** Reset internal cache, etc. *)
|
||||||
|
|
||||||
|
val proof : t -> Proof_trace.t
|
||||||
|
(** Access proof *)
|
||||||
|
|
||||||
|
type hook = t -> Term.t -> (Term.t * Proof_step.id Iter.t) option
|
||||||
|
(** Given a Term.t, try to simplify it. Return [None] if it didn't change.
|
||||||
|
|
||||||
|
A simple example could be a hook that takes a Term.t [t],
|
||||||
|
and if [t] is [app "+" (const x) (const y)] where [x] and [y] are number,
|
||||||
|
returns [Some (const (x+y))], and [None] otherwise.
|
||||||
|
|
||||||
|
The simplifier will take care of simplifying the resulting Term.t further,
|
||||||
|
caching (so that work is not duplicated in subterms), etc.
|
||||||
|
*)
|
||||||
|
|
||||||
|
val add_hook : t -> hook -> unit
|
||||||
|
|
||||||
|
val normalize : t -> Term.t -> (Term.t * Proof_step.id) option
|
||||||
|
(** Normalize a Term.t using all the hooks. This performs
|
||||||
|
a fixpoint, i.e. it only stops when no hook applies anywhere inside
|
||||||
|
the Term.t. *)
|
||||||
|
|
||||||
|
val normalize_t : t -> Term.t -> Term.t * Proof_step.id option
|
||||||
|
(** Normalize a Term.t using all the hooks, along with a proof that the
|
||||||
|
simplification is correct.
|
||||||
|
returns [t, ø] if no simplification occurred. *)
|
||||||
Loading…
Add table
Reference in a new issue