diff --git a/src/plugins/qed/logic.ml b/src/plugins/qed/logic.ml
index b2de4a157e3f8cddbbba1fa90ee614cf3d556bad..ed87768e454b6e42f0c1ada2315c98405893ede8 100644
--- a/src/plugins/qed/logic.ml
+++ b/src/plugins/qed/logic.ml
@@ -304,11 +304,20 @@ sig
   val e_bind : binder -> var -> term -> term
   val e_apply : term -> term list -> term
 
+  (** {3 Local Caches} *)
+
+  type 'a cache
+  val cache : unit -> 'a cache
+  val get : 'a cache -> (term -> 'a) -> term -> 'a
+  val set : 'a cache -> term -> 'a -> unit
+  val lc_get : 'a cache -> (lc_term -> 'a) -> lc_term -> 'a
+  val lc_set : 'a cache -> lc_term -> 'a -> unit
+  val clear : 'a cache -> unit
+
   (** {3 Generalized Substitutions} *)
 
   type sigma
   val sigma : unit -> sigma
-  val sigma_add : sigma -> term Tmap.t -> unit
 
   val e_subst : ?sigma:sigma -> (term -> term) -> term -> term
   [@@deprecated "Might be unsafe in presence of binders"]
@@ -328,9 +337,13 @@ sig
   [@@deprecated "Might be unsafe in presence of binders"]
 
 
-  (** Instantiate top bound variable with the given term *)
-  val lc_closed : term -> bool
+  val lc_empty : term -> bool (** No bound variables *)
+  val lc_closed : term -> bool (** All bound variables are under their binder *)
   val lc_closed_at : int -> term -> bool
+  (** [lc_closed_at n] do not contains bvar with [k < n].
+      Means that the term has no bound-variable that can escape [n] binders
+      uppon the term. *)
+
   val lc_vars : term -> Bvars.t
 
   val lc_term : term -> lc_term
diff --git a/src/plugins/qed/term.ml b/src/plugins/qed/term.ml
index 6b74f90b8c059da7002c7ef92a35da8c97cffeb4..25167c743bbac2bad35c5f8e21ab7738d525a2bd 100644
--- a/src/plugins/qed/term.ml
+++ b/src/plugins/qed/term.ml
@@ -1120,14 +1120,6 @@ struct
     if Z.lt z Z.zero then Negative else
     if Z.lt Z.zero z then Positive else
       Null
-(*
-  let pp fmt a =
-    match a.repr with
-    | Kint z -> Format.pp_print_string fmt (Z.to_string z)
-    | Kreal q -> Format.pp_print_string fmt (Q.to_string q)
-    | Fvar x -> Var.pretty fmt x
-    | _ -> Format.fprintf fmt "#%d" a.id
-*)
 
   let r_affine_rel fz fe c xs ys =
     let a , xs = r_ground Q.add (Q.of_bigint c) [] xs in
@@ -1873,25 +1865,64 @@ struct
   let e_record fxs = c_record fxs
   type record = (Field.t * term) list
 
+  (* -------------------------------------------------------------------------- *)
+  (* --- Smart Constructors                                                 --- *)
+  (* -------------------------------------------------------------------------- *)
+
+  let e_equiv = e_eq
+  let e_sum = addition
+  let e_prod = multiplication
+  let e_opp x = times Z.minus_one x
+  let e_add x y = addition [x;y]
+  let e_sub x y = addition [x;e_opp y]
+  let e_mul x y = multiplication [x;y]
+
+  (* -------------------------------------------------------------------------- *)
+  (* --- Caches                                                             --- *)
+  (* -------------------------------------------------------------------------- *)
+
+  type 'a cache = 'a Tmap.t ref
+
+  let cache () = ref Tmap.empty
+  let get mu f e =
+    try Tmap.find e !mu with Not_found ->
+      let v = f e in mu := Tmap.add e v !mu ; v
+  let set mu e v = mu := Tmap.add e v !mu
+  let clear mu = mu := Tmap.empty
+
+  let lc_set = set
+  let lc_get = get
+
+  (* -------------------------------------------------------------------------- *)
+  (* --- Locally Nameless                                                   --- *)
+  (* -------------------------------------------------------------------------- *)
+
+  let lc_empty e = Bvars.is_empty e.bind
+  let lc_closed e = Bvars.closed e.bind
+  let lc_closed_at n e = Bvars.closed_at n e.bind
+  let lc_vars e = e.bind
+  let lc_repr e = e
+  let lc_term e = e
+
   (* -------------------------------------------------------------------------- *)
   (* --- Non-Binding Morphism                                               --- *)
   (* -------------------------------------------------------------------------- *)
 
   let rebuild f e =
     match e.repr with
-    | Kint _ | Kreal _ | Fvar _ | Bvar _ | True | False -> e
+    | Kint _ | Kreal _ | Fvar _ | True | False -> e
     | Not e -> e_not (f e)
-    | Add xs -> addition (List.map f xs)
-    | Mul xs -> multiplication (List.map f xs)
+    | Add xs -> e_sum (List.map f xs)
+    | Mul xs -> e_prod (List.map f xs)
     | And xs -> e_and (List.map f xs)
-    | Or  xs -> e_or  (List.map f xs)
+    | Or  xs -> e_or (List.map f xs)
     | Mod(x,y) -> e_mod (f x) (f y)
     | Div(x,y) -> e_div (f x) (f y)
     | Eq(x,y)  -> e_eq  (f x) (f y)
     | Neq(x,y) -> e_neq (f x) (f y)
     | Lt(x,y)  -> e_lt  (f x) (f y)
     | Leq(x,y) -> e_leq (f x) (f y)
-    | Times(z,t) -> times z (f t)
+    | Times(z,t) -> e_times z (f t)
     | If(e,a,b) -> e_if (f e) (f a) (f b)
     | Imply(hs,p) -> e_imply (List.map f hs) (f p)
     | Fun(g,xs) -> e_fun g (List.map f xs)
@@ -1900,53 +1931,22 @@ struct
     | Aset(x,y,z) -> e_set (f x) (f y) (f z)
     | Rget(x,g) -> e_getfield (f x) g
     | Rdef gxs -> e_record (List.map (fun (g,x) -> g, f x) gxs)
-    | Apply(e,es) -> c_apply (f e) (List.map f es)
-    | Bind(q,t,e) -> c_bind q t (f e)
-
-  (* -------------------------------------------------------------------------- *)
-  (* --- Smart Constructors                                                 --- *)
-  (* -------------------------------------------------------------------------- *)
-
-  let e_equiv = e_eq
-  let e_sum = addition
-  let e_prod = multiplication
-  let e_opp x = times Z.minus_one x
-  let e_add x y = addition [x;y]
-  let e_sub x y = addition [x;e_opp y]
-  let e_mul x y = multiplication [x;y]
-
-  (* -------------------------------------------------------------------------- *)
-  (* --- Locally Memoized                                                   --- *)
-  (* -------------------------------------------------------------------------- *)
-
-  type sigma = term Tmap.t ref
+    | Bvar _ | Bind _ | Apply _ -> assert false
 
-  let sigma () = ref Tmap.empty
-
-  let cache_find m e = Tmap.find e !m
-  let cache_bind m e v = m := Tmap.add e v !m ; v
-
-  let sigma_add m t = m := Tmap.union (fun _ _ v2 -> v2) !m t
-
-  (* -------------------------------------------------------------------------- *)
-  (* --- Locally Nameless                                                   --- *)
-  (* -------------------------------------------------------------------------- *)
 
   let rec lc_subst_var m x v e =
     if not (Vars.mem x e.vars) then e else
       match e.repr with
       | Fvar y when Var.equal x y -> v
-      | _ ->
-          try cache_find m e
-          with Not_found -> cache_bind m e (rebuild (lc_subst_var m x v) e)
+      | _ -> get m (rebuild (lc_subst_var m x v)) e
 
   let lc_bind x e =
     let k = Bvars.order e.bind in
     let t = tau_of_var x in
-    lc_subst_var (sigma ()) x (c_bvar k t) e
+    lc_subst_var (cache ()) x (c_bvar k t) e
 
   let e_subst_var x v e =
-    lc_subst_var (sigma ()) x v e
+    lc_subst_var (cache ()) x v e
 
   let rec lc_open m k v e =
     if not (Bvars.contains k e.bind) then e else
@@ -1954,22 +1954,37 @@ struct
       | Bvar _ -> v (* e.bind is a singleton that can only contains k *)
       | _ ->
           if is_simple e then e else
-            try cache_find m e
-            with Not_found -> cache_bind m e (rebuild (lc_open m k v) e)
+            get m (rebuild (lc_open m k v)) e
 
   let lc_open_term t e =
     let k = Bvars.order e.bind in
-    lc_open (sigma ()) k t e
+    lc_open (cache ()) k t e
 
   let lc_open x e =
     let k = Bvars.order e.bind in
-    lc_open (sigma ()) k (e_var x) e
+    lc_open (cache ()) k (e_var x) e
 
-  let lc_closed e = Bvars.closed e.bind
-  let lc_closed_at n e = Bvars.closed_at n e.bind
-  let lc_vars e = e.bind
-  let lc_repr e = e
-  let lc_term e = e
+  (* -------------------------------------------------------------------------- *)
+  (* --- General Substitutions                                              --- *)
+  (* -------------------------------------------------------------------------- *)
+
+  type sigma = term cache
+
+  let sigma () = cache ()
+
+  let rec gsubst mu f e =
+    match e.repr with
+    | True | False | Kint _ | Kreal _ | Bvar _ -> e
+    | _ -> get mu (fun e ->
+        let e0 = rebuild (gsubst mu f) e in
+        if lc_closed e0 then
+          try f e0 with Not_found -> e0
+        else e0
+      ) e
+
+  let e_subst ?sigma f e =
+    let cache = match sigma with None -> ref Tmap.empty | Some c -> c in
+    gsubst cache f e
 
   (* -------------------------------------------------------------------------- *)
   (* --- Binders                                                            --- *)
@@ -2045,7 +2060,7 @@ struct
     if do_bind then
       match let_intro_case q x a with
       | None -> c_bind q (tau_of_var x) (lc_bind x a)
-      | Some e -> lc_subst_var (sigma ()) x e a (* case [let x = e ; a] *)
+      | Some e -> lc_subst_var (cache ()) x e a (* case [let x = e ; a] *)
     else a
 
   let rec bind_xs q xs e =
@@ -2066,24 +2081,23 @@ struct
 
   let r_apply = ref (fun _ _ _ -> assert false)
 
-  let rec subst sigma xs d e =
+  let rec subst mu xs d e =
     (* substitute bound variable d+i with xs.(i) for 0 <= i < xs.length *)
     if not (Bvars.overlap d (Array.length xs) e.bind)
     then e else
       match e.repr with
       | Bvar(k,_) -> xs.(k-d)
       | _ ->
-          try cache_find sigma e
-          with Not_found ->
-            cache_bind sigma e
-              begin match e.repr with
-                | Apply(e,es) ->
-                    let e = subst sigma xs d e in
-                    let es = List.map (subst sigma xs d) es in
-                    !r_apply [] e es
-                | _ ->
-                    rebuild (subst sigma xs d) e
-              end
+          get mu
+            begin fun e ->
+              match e.repr with
+              | Apply(e,es) ->
+                  let e = subst mu xs d e in
+                  let es = List.map (subst mu xs d) es in
+                  !r_apply [] e es
+              | _ ->
+                  rebuild (subst mu xs d) e
+            end e
 
   let rec apply xs a es =
     match a.repr , es with
@@ -2091,37 +2105,16 @@ struct
     | _ ->
         let core =
           if xs=[] then a else
-            let sigma = sigma () in
+            let mu = cache () in
             let xs = Array.of_list xs in
             let d = Bvars.order a.bind + 1 - Array.length xs in
-            subst sigma xs d a
+            subst mu xs d a
         in c_apply core es
 
   let () = r_apply := apply
 
   let e_apply e es = apply [] e es
 
-  (* -------------------------------------------------------------------------- *)
-  (* --- General Substitutions                                              --- *)
-  (* -------------------------------------------------------------------------- *)
-
-  let rec gsubst mu sigma e =
-    match e.repr with
-    | True | False | Kint _ | Kreal _ | Bvar _ -> e
-    | _ ->
-        try cache_find mu e
-        with Not_found ->
-          let e0 = rebuild (gsubst mu sigma) e in
-          let e1 =
-            if lc_closed e0 then
-              try sigma e0 with Not_found -> e0
-            else e0 in
-          cache_bind mu e e1
-
-  let e_subst ?sigma f e =
-    let cache = match sigma with None -> ref Tmap.empty | Some c -> c in
-    gsubst cache f e
-
   (* -------------------------------------------------------------------------- *)
   (* --- Iterators                                                          --- *)
   (* -------------------------------------------------------------------------- *)