]> matita.cs.unibo.it Git - helm.git/commitdiff
Brand new implementation based on functors taking a strategy in input.
authorClaudio Sacerdoti Coen <claudio.sacerdoticoen@unibo.it>
Mon, 2 Dec 2002 14:35:13 +0000 (14:35 +0000)
committerClaudio Sacerdoti Coen <claudio.sacerdoticoen@unibo.it>
Mon, 2 Dec 2002 14:35:13 +0000 (14:35 +0000)
Several different strategies have been implemented. Unfortunately many
of them are incomparable and there are critical examples where only some
of them terminate in reasonable time.

Removing the functor/module stuff does not bring any sensible performance
improvement even for simple strategies (where most of the functions are
just identity fuctions that can be inlined when not crossing functor
boundaries).

helm/ocaml/cic_proof_checking/cicReductionMachine.ml

index 55db97045845401538bd4a4557963c17ad32b858..30b688264776e8f2c77816fdf52e5ece0577daa5 100644 (file)
@@ -45,422 +45,689 @@ let debug t env s =
    end
 ;;
 
-type env = Cic.term list;;
-type stack = Cic.term list;;
-type config =
- int * env * Cic.term Cic.explicit_named_substitution * Cic.term * stack;;
+module type Strategy =
+ sig
+  type stack_term
+  type env_term
+  type ens_term
+  val to_stack : Cic.term -> stack_term
+  val to_stack_list : Cic.term list -> stack_term list
+  val to_env : Cic.term -> env_term
+  val to_ens : Cic.term -> ens_term
+  val from_stack :
+   unwind:
+    (int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+      Cic.term -> Cic.term) ->
+   stack_term -> Cic.term
+  val from_stack_list :
+   unwind:
+    (int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+      Cic.term -> Cic.term) ->
+   stack_term list -> Cic.term list
+  val from_env : env_term -> Cic.term
+  val from_ens : ens_term -> Cic.term
+  val stack_to_env :
+   reduce:
+    (int * env_term list * ens_term Cic.explicit_named_substitution *
+      Cic.term * stack_term list -> Cic.term) ->
+   unwind:
+    (int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+      Cic.term -> Cic.term) ->
+   stack_term -> env_term
+  val compute_to_env :
+   reduce:
+    (int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term *
+      stack_term list -> Cic.term) ->
+   unwind:
+    (int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+      Cic.term -> Cic.term) ->
+   int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+    Cic.term -> env_term
+  val compute_to_stack :
+   reduce:
+    (int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term *
+      stack_term list -> Cic.term) ->
+   unwind:
+    (int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+      Cic.term -> Cic.term) ->
+   int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+    Cic.term -> stack_term
+ end
+;;
 
-let call_by_name = false;;   (* false means call_by_value *)
+module CallByNameStrategy =
+ struct
+  type stack_term = Cic.term
+  type env_term = Cic.term
+  type ens_term = Cic.term
+  let to_stack v = v
+  let to_stack_list l = l
+  let to_env v = v
+  let to_ens v = v
+  let from_stack ~unwind v = v
+  let from_stack_list ~unwind l = l
+  let from_env v = v
+  let from_ens v = v
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens t = unwind k e ens t
+  let compute_to_env ~reduce ~unwind k e ens t = unwind k e ens t
+ end
+;;
 
-(* k is the length of the environment e *)
-(* m is the current depth inside the term *)
-let unwind' m k e ens t = 
- let module C = Cic in
- let module S = CicSubstitution in
-  if k = 0 && ens = [] then
-   t
-  else 
-   let rec unwind_aux m =
-    function
-       C.Rel n as t ->
-        if n <= m then t else
-         let d =
-          try
-           Some (List.nth e (n-m-1))
-          with _ -> None
-         in
-          (match d with 
-              Some t' ->
-               if m = 0 then t' else S.lift m t'
-            | None -> C.Rel (n-k)
-          )
-     | C.Var (uri,exp_named_subst) ->
+module CallByValueStrategy =
+ struct
+  type stack_term = Cic.term
+  type env_term = Cic.term
+  type ens_term = Cic.term
+  let to_stack v = v
+  let to_stack_list l = l
+  let to_env v = v
+  let to_ens v = v
+  let from_stack ~unwind v = v
+  let from_stack_list ~unwind l = l
+  let from_env v = v
+  let from_ens v = v
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens t = reduce (k,e,ens,t,[])
+  let compute_to_env ~reduce ~unwind k e ens t = reduce (k,e,ens,t,[])
+ end
+;;
+
+module CallByValueStrategyByNameOnConstants =
+ struct
+  type stack_term = Cic.term
+  type env_term = Cic.term
+  type ens_term = Cic.term
+  let to_stack v = v
+  let to_stack_list l = l
+  let to_env v = v
+  let to_ens v = v
+  let from_stack ~unwind v = v
+  let from_stack_list ~unwind l = l
+  let from_env v = v
+  let from_ens v = v
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens =
+   function
+      Cic.Const _ as t -> unwind k e ens t    
+    | t -> reduce (k,e,ens,t,[])
+  let compute_to_env ~reduce ~unwind k e ens =
+   function
+      Cic.Const _ as t -> unwind k e ens t    
+    | t -> reduce (k,e,ens,t,[])
+ end
+;;
+
+module LazyCallByValueStrategy =
+ struct
+  type stack_term = Cic.term lazy_t
+  type env_term = Cic.term lazy_t
+  type ens_term = Cic.term lazy_t
+  let to_stack v = lazy v
+  let to_stack_list l = List.map to_stack l
+  let to_env v = lazy v
+  let to_ens v = lazy v
+  let from_stack ~unwind v = Lazy.force v
+  let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+  let from_env v = Lazy.force v
+  let from_ens v = Lazy.force v
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens t = lazy (reduce (k,e,ens,t,[]))
+  let compute_to_env ~reduce ~unwind k e ens t = lazy (reduce (k,e,ens,t,[]))
+ end
+;;
+
+module LazyCallByValueStrategyByNameOnConstants =
+ struct
+  type stack_term = Cic.term lazy_t
+  type env_term = Cic.term lazy_t
+  type ens_term = Cic.term lazy_t
+  let to_stack v = lazy v
+  let to_stack_list l = List.map to_stack l
+  let to_env v = lazy v
+  let to_ens v = lazy v
+  let from_stack ~unwind v = Lazy.force v
+  let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+  let from_env v = Lazy.force v
+  let from_ens v = Lazy.force v
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens t =
+   lazy (
+    match t with
+       Cic.Const _ as t -> unwind k e ens t    
+     | t -> reduce (k,e,ens,t,[]))
+  let compute_to_env ~reduce ~unwind k e ens t =
+   lazy (
+    match t with
+       Cic.Const _ as t -> unwind k e ens t    
+     | t -> reduce (k,e,ens,t,[]))
+ end
+;;
+
+module LazyCallByNameStrategy =
+ struct
+  type stack_term = Cic.term lazy_t
+  type env_term = Cic.term lazy_t
+  type ens_term = Cic.term lazy_t
+  let to_stack v = lazy v
+  let to_stack_list l = List.map to_stack l
+  let to_env v = lazy v
+  let to_ens v = lazy v
+  let from_stack ~unwind v = Lazy.force v
+  let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+  let from_env v = Lazy.force v
+  let from_ens v = Lazy.force v
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens t = lazy (unwind k e ens t)
+  let compute_to_env ~reduce ~unwind k e ens t = lazy (unwind k e ens t)
+ end
+;;
+
+module
+ LazyCallByValueByNameOnConstantsWhenFromStack_ByNameStrategyWhenFromEnvOrEns
+=
+ struct
+  type stack_term = reduce:bool -> Cic.term
+  type env_term = reduce:bool -> Cic.term
+  type ens_term = reduce:bool -> Cic.term
+  let to_stack v =
+   let value = lazy v in
+    fun ~reduce -> Lazy.force value
+  let to_stack_list l = List.map to_stack l
+  let to_env v =
+   let value = lazy v in
+    fun ~reduce -> Lazy.force value
+  let to_ens v =
+   let value = lazy v in
+    fun ~reduce -> Lazy.force value
+  let from_stack ~unwind v = (v ~reduce:false)
+  let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+  let from_env v = (v ~reduce:true)
+  let from_ens v = (v ~reduce:true)
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens t =
+   let svalue =
+     lazy (
+      match t with
+         Cic.Const _ as t -> unwind k e ens t    
+       | t -> reduce (k,e,ens,t,[])
+     ) in
+   let lvalue =
+    lazy (unwind k e ens t)
+   in
+    fun ~reduce ->
+     if reduce then Lazy.force svalue else Lazy.force lvalue
+  let compute_to_env ~reduce ~unwind k e ens t =
+   let svalue =
+     lazy (
+      match t with
+         Cic.Const _ as t -> unwind k e ens t    
+       | t -> reduce (k,e,ens,t,[])
+     ) in
+   let lvalue =
+    lazy (unwind k e ens t)
+   in
+    fun ~reduce ->
+     if reduce then Lazy.force svalue else Lazy.force lvalue
+ end
+;;
+
+module ClosuresOnStackByValueFromEnvOrEnsStrategy =
+ struct
+  type stack_term =
+   int * Cic.term list * Cic.term Cic.explicit_named_substitution * Cic.term
+  type env_term = Cic.term
+  type ens_term = Cic.term
+  let to_stack v = (0,[],[],v)
+  let to_stack_list l = List.map to_stack l
+  let to_env v = v
+  let to_ens v = v
+  let from_stack ~unwind (k,e,ens,t) = unwind k e ens t
+  let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+  let from_env v = v
+  let from_ens v = v
+  let stack_to_env ~reduce ~unwind (k,e,ens,t) = reduce (k,e,ens,t,[])
+  let compute_to_env ~reduce ~unwind k e ens t =
+   unwind k e ens t
+  let compute_to_stack ~reduce ~unwind k e ens t = (k,e,ens,t)
+ end
+;;
+
+module ClosuresOnStackByValueFromEnvOrEnsByNameOnConstantsStrategy =
+ struct
+  type stack_term =
+   int * Cic.term list * Cic.term Cic.explicit_named_substitution * Cic.term
+  type env_term = Cic.term
+  type ens_term = Cic.term
+  let to_stack v = (0,[],[],v)
+  let to_stack_list l = List.map to_stack l
+  let to_env v = v
+  let to_ens v = v
+  let from_stack ~unwind (k,e,ens,t) = unwind k e ens t
+  let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+  let from_env v = v
+  let from_ens v = v
+  let stack_to_env ~reduce ~unwind (k,e,ens,t) =
+   match t with
+      Cic.Const _ as t -> unwind k e ens t    
+    | t -> reduce (k,e,ens,t,[])
+  let compute_to_env ~reduce ~unwind k e ens t =
+   unwind k e ens t
+  let compute_to_stack ~reduce ~unwind k e ens t = (k,e,ens,t)
+ end
+;;
+
+module Reduction(RS : Strategy) =
+ struct
+  type env = RS.env_term list
+  type ens = RS.ens_term Cic.explicit_named_substitution
+  type stack = RS.stack_term list
+  type config = int * env * ens * Cic.term * stack
+
+  (* k is the length of the environment e *)
+  (* m is the current depth inside the term *)
+  let unwind' m k e ens t = 
+   let module C = Cic in
+   let module S = CicSubstitution in
+    if k = 0 && ens = [] then
+     t
+    else 
+     let rec unwind_aux m =
+      function
+         C.Rel n as t ->
+          if n <= m then t else
+           let d =
+            try
+             Some (RS.from_env (List.nth e (n-m-1)))
+            with _ -> None
+           in
+            (match d with 
+                Some t' ->
+                 if m = 0 then t' else S.lift m t'
+              | None -> C.Rel (n-k)
+            )
+       | C.Var (uri,exp_named_subst) ->
 (*
 prerr_endline ("%%%%%UWVAR " ^ String.concat " ; " (List.map (function (uri,t) -> UriManager.string_of_uri uri ^ " := " ^ CicPp.ppterm t) ens)) ;
 *)
-       if List.exists (function (uri',_) -> UriManager.eq uri' uri) ens then
-        CicSubstitution.lift m (List.assq uri ens)
-       else
-        let params =
-         (match CicEnvironment.get_obj uri with
-             C.Constant _ -> raise ReferenceToConstant
-           | C.Variable (_,_,_,params) -> params
-           | C.CurrentProof _ -> raise ReferenceToCurrentProof
-           | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
-         )
-        in
-         let exp_named_subst' =
-          substaux_in_exp_named_subst params exp_named_subst m 
-         in
-          C.Var (uri,exp_named_subst')
-     | C.Meta (i,l) ->
-        let l' =
-         List.map
-          (function
-              None -> None
-            | Some t -> Some (unwind_aux m t)
-          ) l
-        in
-         C.Meta (i, l')
-     | C.Sort _ as t -> t
-     | C.Implicit as t -> t
-     | C.Cast (te,ty) -> C.Cast (unwind_aux m te, unwind_aux m ty) (*CSC ??? *)
-     | C.Prod (n,s,t) -> C.Prod (n, unwind_aux m s, unwind_aux (m + 1) t)
-     | C.Lambda (n,s,t) -> C.Lambda (n, unwind_aux m s, unwind_aux (m + 1) t)
-     | C.LetIn (n,s,t) -> C.LetIn (n, unwind_aux m s, unwind_aux (m + 1) t)
-     | C.Appl l -> C.Appl (List.map (unwind_aux m) l)
-     | C.Const (uri,exp_named_subst) ->
-        let params =
-         (match CicEnvironment.get_obj uri with
-             C.Constant (_,_,_,params) -> params
-           | C.Variable _ -> raise ReferenceToVariable
-           | C.CurrentProof (_,_,_,_,params) -> params
-           | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
-         )
-        in
-         let exp_named_subst' =
-          substaux_in_exp_named_subst params exp_named_subst m 
-         in
-          C.Const (uri,exp_named_subst')
-     | C.MutInd (uri,i,exp_named_subst) ->
-        let params =
-         (match CicEnvironment.get_obj uri with
-             C.Constant _ -> raise ReferenceToConstant
-           | C.Variable _ -> raise ReferenceToVariable
-           | C.CurrentProof _ -> raise ReferenceToCurrentProof
-           | C.InductiveDefinition (_,params,_) -> params
-         )
-        in
-         let exp_named_subst' =
-          substaux_in_exp_named_subst params exp_named_subst m 
-         in
-          C.MutInd (uri,i,exp_named_subst')
-     | C.MutConstruct (uri,i,j,exp_named_subst) ->
-        let params =
-         (match CicEnvironment.get_obj uri with
-             C.Constant _ -> raise ReferenceToConstant
-           | C.Variable _ -> raise ReferenceToVariable
-           | C.CurrentProof _ -> raise ReferenceToCurrentProof
-           | C.InductiveDefinition (_,params,_) -> params
-         )
-        in
-         let exp_named_subst' =
-          substaux_in_exp_named_subst params exp_named_subst m 
-         in
-          C.MutConstruct (uri,i,j,exp_named_subst')
-     | C.MutCase (sp,i,outt,t,pl) ->
-        C.MutCase (sp,i,unwind_aux m outt, unwind_aux m t,
-         List.map (unwind_aux m) pl)
-     | C.Fix (i,fl) ->
-        let len = List.length fl in
-        let substitutedfl =
-         List.map
-          (fun (name,i,ty,bo) ->
-            (name, i, unwind_aux m ty, unwind_aux (m+len) bo))
-           fl
-        in
-         C.Fix (i, substitutedfl)
-     | C.CoFix (i,fl) ->
-        let len = List.length fl in
-        let substitutedfl =
-         List.map
-          (fun (name,ty,bo) -> (name, unwind_aux m ty, unwind_aux (m+len) bo))
-           fl
-        in
-         C.CoFix (i, substitutedfl)
-   and substaux_in_exp_named_subst params exp_named_subst' m  =
-(*CSC: Idea di Andrea di ordinare compatibilmente con l'ordine dei params
-    let ens' =
-     List.map (function (uri,t) -> uri, unwind_aux m t) exp_named_subst' @
-(*CSC: qui liftiamo tutti gli ens anche se magari me ne servono la meta'!!! *)
-      List.map (function (uri,t) -> uri, CicSubstitution.lift m t) ens
-    in
-    let rec filter_and_lift =
-     function
-        [] -> []
-      | uri::tl ->
-         let r = filter_and_lift tl in
-          (try
-            (uri,(List.assq uri ens'))::r
-           with
-            Not_found -> r
-          )
-    in
-     filter_and_lift params
-*)
-
-(*CSC: invece di concatenare sarebbe meglio rispettare l'ordine dei params *)
-(*CSC: e' vero???? una veloce prova non sembra confermare la teoria        *)
-
-(*CSC: codice copiato e modificato dalla cicSubstitution.subst_vars *)
-(*CSC: codice altamente inefficiente *)
-    let rec filter_and_lift already_instantiated =
-     function
-        [] -> []
-      | (uri,t)::tl when
-          List.for_all
-           (function (uri',_) -> not (UriManager.eq uri uri')) exp_named_subst'
-          &&
-           not (List.mem uri already_instantiated)
-          &&
-           List.mem uri params
-         ->
-          (uri,CicSubstitution.lift m t) ::
-           (filter_and_lift (uri::already_instantiated) tl)
-      | _::tl -> filter_and_lift already_instantiated tl
+         if List.exists (function (uri',_) -> UriManager.eq uri' uri) ens then
+          CicSubstitution.lift m (RS.from_ens (List.assq uri ens))
+         else
+          let params =
+           (match CicEnvironment.get_obj uri with
+               C.Constant _ -> raise ReferenceToConstant
+             | C.Variable (_,_,_,params) -> params
+             | C.CurrentProof _ -> raise ReferenceToCurrentProof
+             | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
+           )
+          in
+           let exp_named_subst' =
+            substaux_in_exp_named_subst params exp_named_subst m 
+           in
+            C.Var (uri,exp_named_subst')
+       | C.Meta (i,l) ->
+          let l' =
+           List.map
+            (function
+                None -> None
+              | Some t -> Some (unwind_aux m t)
+            ) l
+          in
+           C.Meta (i, l')
+       | C.Sort _ as t -> t
+       | C.Implicit as t -> t
+       | C.Cast (te,ty) -> C.Cast (unwind_aux m te, unwind_aux m ty) (*CSC ???*)
+       | C.Prod (n,s,t) -> C.Prod (n, unwind_aux m s, unwind_aux (m + 1) t)
+       | C.Lambda (n,s,t) -> C.Lambda (n, unwind_aux m s, unwind_aux (m + 1) t)
+       | C.LetIn (n,s,t) -> C.LetIn (n, unwind_aux m s, unwind_aux (m + 1) t)
+       | C.Appl l -> C.Appl (List.map (unwind_aux m) l)
+       | C.Const (uri,exp_named_subst) ->
+          let params =
+           (match CicEnvironment.get_obj uri with
+               C.Constant (_,_,_,params) -> params
+             | C.Variable _ -> raise ReferenceToVariable
+             | C.CurrentProof (_,_,_,_,params) -> params
+             | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
+           )
+          in
+           let exp_named_subst' =
+            substaux_in_exp_named_subst params exp_named_subst m 
+           in
+            C.Const (uri,exp_named_subst')
+       | C.MutInd (uri,i,exp_named_subst) ->
+          let params =
+           (match CicEnvironment.get_obj uri with
+               C.Constant _ -> raise ReferenceToConstant
+             | C.Variable _ -> raise ReferenceToVariable
+             | C.CurrentProof _ -> raise ReferenceToCurrentProof
+             | C.InductiveDefinition (_,params,_) -> params
+           )
+          in
+           let exp_named_subst' =
+            substaux_in_exp_named_subst params exp_named_subst m 
+           in
+            C.MutInd (uri,i,exp_named_subst')
+       | C.MutConstruct (uri,i,j,exp_named_subst) ->
+          let params =
+           (match CicEnvironment.get_obj uri with
+               C.Constant _ -> raise ReferenceToConstant
+             | C.Variable _ -> raise ReferenceToVariable
+             | C.CurrentProof _ -> raise ReferenceToCurrentProof
+             | C.InductiveDefinition (_,params,_) -> params
+           )
+          in
+           let exp_named_subst' =
+            substaux_in_exp_named_subst params exp_named_subst m 
+           in
+            C.MutConstruct (uri,i,j,exp_named_subst')
+       | C.MutCase (sp,i,outt,t,pl) ->
+          C.MutCase (sp,i,unwind_aux m outt, unwind_aux m t,
+           List.map (unwind_aux m) pl)
+       | C.Fix (i,fl) ->
+          let len = List.length fl in
+          let substitutedfl =
+           List.map
+            (fun (name,i,ty,bo) ->
+              (name, i, unwind_aux m ty, unwind_aux (m+len) bo))
+             fl
+          in
+           C.Fix (i, substitutedfl)
+       | C.CoFix (i,fl) ->
+          let len = List.length fl in
+          let substitutedfl =
+           List.map
+            (fun (name,ty,bo) -> (name, unwind_aux m ty, unwind_aux (m+len) bo))
+             fl
+          in
+           C.CoFix (i, substitutedfl)
+     and substaux_in_exp_named_subst params exp_named_subst' m  =
+  (*CSC: Idea di Andrea di ordinare compatibilmente con l'ordine dei params
+      let ens' =
+       List.map (function (uri,t) -> uri, unwind_aux m t) exp_named_subst' @
+  (*CSC: qui liftiamo tutti gli ens anche se magari me ne servono la meta'!!! *)
+        List.map (function (uri,t) -> uri, CicSubstitution.lift m t) ens
+      in
+      let rec filter_and_lift =
+       function
+          [] -> []
+        | uri::tl ->
+           let r = filter_and_lift tl in
+            (try
+              (uri,(List.assq uri ens'))::r
+             with
+              Not_found -> r
+            )
+      in
+       filter_and_lift params
+  *)
+  
+  (*CSC: invece di concatenare sarebbe meglio rispettare l'ordine dei params *)
+  (*CSC: e' vero???? una veloce prova non sembra confermare la teoria        *)
+  
+  (*CSC: codice copiato e modificato dalla cicSubstitution.subst_vars *)
+  (*CSC: codice altamente inefficiente *)
+      let rec filter_and_lift already_instantiated =
+       function
+          [] -> []
+        | (uri,t)::tl when
+            List.for_all
+             (function (uri',_)-> not (UriManager.eq uri uri')) exp_named_subst'
+            &&
+             not (List.mem uri already_instantiated)
+            &&
+             List.mem uri params
+           ->
+            (uri,CicSubstitution.lift m (RS.from_ens t)) ::
+             (filter_and_lift (uri::already_instantiated) tl)
+        | _::tl -> filter_and_lift already_instantiated tl
 (*
-    | (uri,_)::tl ->
+        | (uri,_)::tl ->
 prerr_endline ("---- SKIPPO " ^ UriManager.string_of_uri uri) ;
 if List.for_all (function (uri',_) -> not (UriManager.eq uri uri')) exp_named_subst' then prerr_endline "---- OK1" ;
 prerr_endline ("++++ uri " ^ UriManager.string_of_uri uri ^ " not in " ^ String.concat " ; " (List.map UriManager.string_of_uri params)) ;
 if List.mem uri params then prerr_endline "---- OK2" ;
         filter_and_lift tl
 *)
-    in
-     List.map (function (uri,t) -> uri, unwind_aux m t) exp_named_subst' @
-      (filter_and_lift [] (List.rev ens))
-   in
-    unwind_aux m t          
-;;
-
-let unwind =
- unwind' 0 
-;;
-
-let reduce context : config -> Cic.term = 
- let module C = Cic in
- let module S = CicSubstitution in 
- let rec reduce =
-  function
-     (k, e, _, (C.Rel n as t), s) ->
-      let d =
-       try
-        Some (List.nth e (n-1))
-       with
-        _ ->
+      in
+       List.map (function (uri,t) -> uri, unwind_aux m t) exp_named_subst' @
+        (filter_and_lift [] (List.rev ens))
+     in
+      unwind_aux m t          
+  ;;
+  
+  let unwind =
+   unwind' 0 
+  ;;
+  
+  let reduce context : config -> Cic.term = 
+   let module C = Cic in
+   let module S = CicSubstitution in 
+   let rec reduce =
+    function
+       (k, e, _, (C.Rel n as t), s) ->
+        let d =
          try
-          begin
-           match List.nth context (n - 1 - k) with
-              None -> assert false
-            | Some (_,C.Decl _) -> None
-            | Some (_,C.Def x) -> Some (S.lift (n - k) x)
-          end
+          Some (RS.from_env (List.nth e (n-1)))
          with
-          _ -> None
-      in
-       (match d with 
-           Some t' -> reduce (0,[],[],t',s)
-         | None ->
-            if s = [] then
-             C.Rel (n-k)
-            else C.Appl (C.Rel (n-k)::s)
-       )
-   | (k, e, ens, (C.Var (uri,exp_named_subst) as t), s) -> 
-       if List.exists (function (uri',_) -> UriManager.eq uri' uri) ens then
-        reduce (0, [], [], List.assq uri ens, s)
-       else
+          _ ->
+           try
+            begin
+             match List.nth context (n - 1 - k) with
+                None -> assert false
+              | Some (_,C.Decl _) -> None
+              | Some (_,C.Def x) -> Some (S.lift (n - k) x)
+            end
+           with
+            _ -> None
+        in
+         (match d with 
+             Some t' -> reduce (0,[],[],t',s)
+           | None ->
+              if s = [] then
+               C.Rel (n-k)
+              else C.Appl (C.Rel (n-k)::(RS.from_stack_list ~unwind s))
+         )
+     | (k, e, ens, (C.Var (uri,exp_named_subst) as t), s) -> 
+         if List.exists (function (uri',_) -> UriManager.eq uri' uri) ens then
+          reduce (0, [], [], RS.from_ens (List.assq uri ens), s)
+         else
+          (match CicEnvironment.get_obj uri with
+              C.Constant _ -> raise ReferenceToConstant
+            | C.CurrentProof _ -> raise ReferenceToCurrentProof
+            | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
+            | C.Variable (_,None,_,_) ->
+               let t' = unwind k e ens t in
+                if s = [] then t' else
+                 C.Appl (t'::(RS.from_stack_list ~unwind s))
+            | C.Variable (_,Some body,_,_) ->
+               let ens' = push_exp_named_subst k e ens exp_named_subst in
+                reduce (0, [], ens', body, s)
+          )
+     | (k, e, ens, (C.Meta _ as t), s) ->
+        let t' = unwind k e ens t in
+         if s = [] then t' else C.Appl (t'::(RS.from_stack_list ~unwind s))
+     | (k, e, _, (C.Sort _ as t), s) -> t (* s should be empty *)
+     | (k, e, _, (C.Implicit as t), s) -> t (* s should be empty *)
+     | (k, e, ens, (C.Cast (te,ty) as t), s) ->
+        reduce (k, e, ens, te, s) (* s should be empty *)
+     | (k, e, ens, (C.Prod _ as t), s) ->
+         unwind k e ens t (* s should be empty *)
+     | (k, e, ens, (C.Lambda (_,_,t) as t'), []) -> unwind k e ens t' 
+     | (k, e, ens, C.Lambda (_,_,t), p::s) ->
+         reduce (k+1, (RS.stack_to_env ~reduce ~unwind p)::e, ens, t,s)
+     | (k, e, ens, (C.LetIn (_,m,t) as t'), s) ->
+        let m' = RS.compute_to_env ~reduce ~unwind k e ens m in
+         reduce (k+1, m'::e, ens, t, s)
+     | (_, _, _, C.Appl [], _) -> raise (Impossible 1)
+     | (k, e, ens, C.Appl (he::tl), s) ->
+        let tl' =
+         List.map
+          (function t -> RS.compute_to_stack ~reduce ~unwind k e ens t) tl
+        in
+         reduce (k, e, ens, he, (List.append tl') s)
+  (* CSC: Old Dead Code 
+     | (k, e, ens, C.Appl ((C.Lambda _ as he)::tl), s) 
+     | (k, e, ens, C.Appl ((C.Const _ as he)::tl), s)  
+     | (k, e, ens, C.Appl ((C.MutCase _ as he)::tl), s) 
+     | (k, e, ens, C.Appl ((C.Fix _ as he)::tl), s) ->
+  (* strict evaluation, but constants are NOT unfolded *)
+        let red =
+         function
+            C.Const _ as t -> unwind k e ens t
+          | t -> reduce (k,e,ens,t,[])
+        in
+         let tl' = List.map red tl in
+          reduce (k, e, ens, he , List.append tl' s)
+     | (k, e, ens, C.Appl l, s) ->
+         C.Appl (List.append (List.map (unwind k e ens) l) s)
+  *)
+     | (k, e, ens, (C.Const (uri,exp_named_subst) as t), s) ->
         (match CicEnvironment.get_obj uri with
-            C.Constant _ -> raise ReferenceToConstant
-          | C.CurrentProof _ -> raise ReferenceToCurrentProof
-          | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
-          | C.Variable (_,None,_,_) ->
+            C.Constant (_,Some body,_,_) ->
+             let ens' = push_exp_named_subst k e ens exp_named_subst in
+              (* constants are closed *)
+              reduce (0, [], ens', body, s) 
+          | C.Constant (_,None,_,_) ->
              let t' = unwind k e ens t in
-              if s = [] then t' else C.Appl (t'::s)
-          | C.Variable (_,Some body,_,_) ->
+              if s = [] then t' else C.Appl (t'::(RS.from_stack_list ~unwind s))
+          | C.Variable _ -> raise ReferenceToVariable
+          | C.CurrentProof (_,_,body,_,_) ->
              let ens' = push_exp_named_subst k e ens exp_named_subst in
+              (* constants are closed *)
               reduce (0, [], ens', body, s)
+          | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
         )
-   | (k, e, ens, (C.Meta _ as t), s) ->
-      let t' = unwind k e ens t in
-       if s = [] then t' else C.Appl (t'::s)
-   | (k, e, _, (C.Sort _ as t), s) -> t (* s should be empty *)
-   | (k, e, _, (C.Implicit as t), s) -> t (* s should be empty *)
-   | (k, e, ens, (C.Cast (te,ty) as t), s) ->
-      reduce (k, e, ens, te, s) (* s should be empty *)
-   | (k, e, ens, (C.Prod _ as t), s) -> unwind k e ens t (* s should be empty *)
-   | (k, e, ens, (C.Lambda (_,_,t) as t'), []) -> unwind k e ens t' 
-   | (k, e, ens, C.Lambda (_,_,t), p::s) ->
-       reduce (k+1, p::e, ens, t,s) 
-   (* lazy *)
-   | (k, e, ens, (C.LetIn (_,m,t) as t'), s) when call_by_name ->
-      let m' = unwind k e ens m in reduce (k+1, m'::e, ens, t, s)
-   (* strict *)
-   | (k, e, ens, (C.LetIn (_,m,t) as t'), s) ->
-      let m' = reduce (k,e,ens,m,[]) in reduce (k+1,m'::e,ens,t,s)
-   | (_, _, _, C.Appl [], _) -> raise (Impossible 1)
-   (* lazy *)
-   | (k, e, ens, C.Appl (he::tl), s) when call_by_name ->
-      let tl' = List.map (unwind k e ens) tl in
-       reduce (k, e, ens, he, (List.append tl' s))
-   (* strict, but constants are NOT unfolded *)
-   | (k, e, ens, C.Appl (he::tl), s) ->
-      (* constants are NOT unfolded *)
-      let red =
-       function
-          C.Const _ as t -> unwind k e ens t    
-        | t -> reduce (k,e,ens,t,[])
-      in
-       let tl' = List.map red tl in
-        reduce (k, e, ens, he , List.append tl' s) 
-(* 
-   | (k, e, ens, C.Appl ((C.Lambda _ as he)::tl), s) 
-   | (k, e, ens, C.Appl ((C.Const _ as he)::tl), s)  
-   | (k, e, ens, C.Appl ((C.MutCase _ as he)::tl), s) 
-   | (k, e, ens, C.Appl ((C.Fix _ as he)::tl), s) ->
-(* strict evaluation, but constants are NOT unfolded *)
-      let red =
-       function
-          C.Const _ as t -> unwind k e ens t
-        | t -> reduce (k,e,ens,t,[])
-      in
-       let tl' = List.map red tl in
-        reduce (k, e, ens, he , List.append tl' s)
-   | (k, e, ens, C.Appl l, s) ->
-       C.Appl (List.append (List.map (unwind k e ens) l) s)
-*)
-   | (k, e, ens, (C.Const (uri,exp_named_subst) as t), s) ->
-      (match CicEnvironment.get_obj uri with
-          C.Constant (_,Some body,_,_) ->
-           let ens' = push_exp_named_subst k e ens exp_named_subst in
-            (* constants are closed *)
-            reduce (0, [], ens', body, s) 
-        | C.Constant (_,None,_,_) ->
-           let t' = unwind k e ens t in
-            if s = [] then t' else C.Appl (t'::s)
-        | C.Variable _ -> raise ReferenceToVariable
-        | C.CurrentProof (_,_,body,_,_) ->
-           let ens' = push_exp_named_subst k e ens exp_named_subst in
-            (* constants are closed *)
-            reduce (0, [], ens', body, s)
-        | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
-      )
-   | (k, e, ens, (C.MutInd _ as t),s) ->
-      let t' = unwind k e ens t in 
-       if s = [] then t' else C.Appl (t'::s)
-   | (k, e, ens, (C.MutConstruct _ as t),s) -> 
-       let t' = unwind k e ens t in
-        if s = [] then t' else C.Appl (t'::s)
-   | (k, e, ens, (C.MutCase (mutind,i,_,term,pl) as t),s) ->
-      let decofix =
-       function
-          C.CoFix (i,fl) as t ->
-           let (_,_,body) = List.nth fl i in
-            let body' =
-             let counter = ref (List.length fl) in
-              List.fold_right
-               (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
-               fl
-               body
-            in
-             (* the term is the result of a reduction; *)
-             (* so it is already unwinded.             *)
-             reduce (0,[],[],body',[])
-        | C.Appl (C.CoFix (i,fl) :: tl) ->
-           let (_,_,body) = List.nth fl i in
-            let body' =
-             let counter = ref (List.length fl) in
-              List.fold_right
-               (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
-               fl
-               body
-            in
-             (* the term is the result of a reduction; *)
-             (* so it is already unwinded.             *)
-             reduce (0,[],[],body',tl)
-        | t -> t
-      in
-       (match decofix (reduce (k,e,ens,term,[])) with
-           C.MutConstruct (_,_,j,_) ->
-            reduce (k, e, ens, (List.nth pl (j-1)), s)
-         | C.Appl (C.MutConstruct (_,_,j,_) :: tl) ->
-            let (arity, r) =
-             match CicEnvironment.get_obj mutind with
-                C.InductiveDefinition (tl,ingredients,r) ->
-                  let (_,_,arity,_) = List.nth tl i in
-                   (arity,r)
-              | _ -> raise WrongUriToInductiveDefinition
-            in
-             let ts =
-              let num_to_eat = r in
-               let rec eat_first =
-                function
-                   (0,l) -> l
-                 | (n,he::tl) when n > 0 -> eat_first (n - 1, tl)
-                 | _ -> raise (Impossible 5)
+     | (k, e, ens, (C.MutInd _ as t),s) ->
+        let t' = unwind k e ens t in 
+         if s = [] then t' else C.Appl (t'::(RS.from_stack_list ~unwind s))
+     | (k, e, ens, (C.MutConstruct _ as t),s) -> 
+         let t' = unwind k e ens t in
+          if s = [] then t' else C.Appl (t'::(RS.from_stack_list ~unwind s))
+     | (k, e, ens, (C.MutCase (mutind,i,_,term,pl) as t),s) ->
+        let decofix =
+         function
+            C.CoFix (i,fl) as t ->
+             let (_,_,body) = List.nth fl i in
+              let body' =
+               let counter = ref (List.length fl) in
+                List.fold_right
+                 (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
+                 fl
+                 body
+              in
+               (* the term is the result of a reduction; *)
+               (* so it is already unwinded.             *)
+               reduce (0,[],[],body',[])
+          | C.Appl (C.CoFix (i,fl) :: tl) ->
+             let (_,_,body) = List.nth fl i in
+              let body' =
+               let counter = ref (List.length fl) in
+                List.fold_right
+                 (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
+                 fl
+                 body
+              in
+               (* the term is the result of a reduction; *)
+               (* so it is already unwinded.             *)
+               reduce (0,[],[],body',RS.to_stack_list tl)
+          | t -> t
+        in
+         (match decofix (reduce (k,e,ens,term,[])) with
+             C.MutConstruct (_,_,j,_) ->
+              reduce (k, e, ens, (List.nth pl (j-1)), s)
+           | C.Appl (C.MutConstruct (_,_,j,_) :: tl) ->
+              let (arity, r) =
+               match CicEnvironment.get_obj mutind with
+                  C.InductiveDefinition (tl,ingredients,r) ->
+                    let (_,_,arity,_) = List.nth tl i in
+                     (arity,r)
+                | _ -> raise WrongUriToInductiveDefinition
+              in
+               let ts =
+                let num_to_eat = r in
+                 let rec eat_first =
+                  function
+                     (0,l) -> l
+                   | (n,he::tl) when n > 0 -> eat_first (n - 1, tl)
+                   | _ -> raise (Impossible 5)
+                 in
+                  eat_first (num_to_eat,tl)
                in
-                eat_first (num_to_eat,tl)
-             in
-              (* ts are already unwinded because they are a sublist of tl *)
-              reduce (k, e, ens, (List.nth pl (j-1)),(ts@s)) 
-        | C.Cast _ | C.Implicit ->
-            raise (Impossible 2) (* we don't trust our whd ;-) *)
-         | _ ->
-           let t' = unwind k e ens t in
-            if s = [] then t' else C.Appl (t'::s)
-       )
-   | (k, e, ens, (C.Fix (i,fl) as t), s) ->
-      let (_,recindex,_,body) = List.nth fl i in
-       let recparam =
-        try
-         Some (List.nth s recindex)
-        with
-         _ -> None
-       in
-        (match recparam with
-            Some recparam ->
-             (match reduce (0,[],[],recparam,[]) with
-                 (* match recparam with *) 
-                 C.MutConstruct _
-               | C.Appl ((C.MutConstruct _)::_) ->
-                  (* OLD 
-                  let body' =
-                   let counter = ref (List.length fl) in
-                    List.fold_right
-                     (fun _ -> decr counter ; S.subst (C.Fix (!counter,fl)))
-                     fl
-                     body
-                  in 
-                   reduce (k, e, ens, body', s) *)
-                  (* NEW *)
-                  let leng = List.length fl in
-                  let fl' = 
-                   let unwind_fl (name,recindex,typ,body) = 
-                    (name,recindex,unwind k e ens typ,
-                      unwind' leng k e ens body)
-                   in
-                   List.map unwind_fl fl
-                  in
-                   let new_env =
-                    let counter = ref 0 in
-                    let rec build_env e =
-                     if !counter = leng then e
-                     else
-                      (incr counter ; build_env ((C.Fix (!counter -1, fl'))::e))
+                (* ts are already unwinded because they are a sublist of tl *)
+                reduce (k, e, ens, (List.nth pl (j-1)), (RS.to_stack_list ts)@s)
+          | C.Cast _ | C.Implicit ->
+              raise (Impossible 2) (* we don't trust our whd ;-) *)
+           | _ ->
+             let t' = unwind k e ens t in
+              if s = [] then t' else C.Appl (t'::(RS.from_stack_list ~unwind s))
+         )
+     | (k, e, ens, (C.Fix (i,fl) as t), s) ->
+        let (_,recindex,_,body) = List.nth fl i in
+         let recparam =
+          try
+           Some (RS.from_stack ~unwind (List.nth s recindex))
+          with
+           _ -> None
+         in
+          (match recparam with
+              Some recparam ->
+               (match reduce (0,[],[],recparam,[]) with
+                   (* match recparam with *) 
+                   C.MutConstruct _
+                 | C.Appl ((C.MutConstruct _)::_) ->
+                    (* OLD 
+                    let body' =
+                     let counter = ref (List.length fl) in
+                      List.fold_right
+                       (fun _ -> decr counter ; S.subst (C.Fix (!counter,fl)))
+                       fl
+                       body
+                    in 
+                     reduce (k, e, ens, body', s) *)
+                    (* NEW *)
+                    let leng = List.length fl in
+                    let fl' = 
+                     let unwind_fl (name,recindex,typ,body) = 
+                      (name,recindex,unwind k e ens typ,
+                        unwind' leng k e ens body)
+                     in
+                     List.map unwind_fl fl
                     in
-                     build_env e
-                   in
-                    reduce (k+leng, new_env, ens, body, s)  
-               | _ ->
-                 let t' = unwind k e ens t in 
-                  if s = [] then t' else C.Appl (t'::s)
-             )
-          | None ->
-             let t' = unwind k e ens t in 
-              if s = [] then t' else C.Appl (t'::s)
-        )
-   | (k, e, ens, (C.CoFix (i,fl) as t),s) ->
-      let t' = unwind k e ens t in 
-       if s = [] then t' else C.Appl (t'::s)
- and push_exp_named_subst k e ens =
-  function
-     [] -> ens
-   | (uri,t)::tl -> push_exp_named_subst k e ((uri,unwind k e ens t)::ens) tl
- in
-  reduce
-;;
-
-let rec whd context t = reduce context (0, [], [], t, []);;
-
+                     let new_env =
+                      let counter = ref 0 in
+                      let rec build_env e =
+                       if !counter = leng then e
+                       else
+                        (incr counter ;
+                         build_env ((RS.to_env (C.Fix (!counter -1, fl')))::e))
+                      in
+                       build_env e
+                     in
+                      reduce (k+leng, new_env, ens, body, s)  
+                 | _ ->
+                   let t' = unwind k e ens t in 
+                    if s = [] then t' else
+                     C.Appl (t'::(RS.from_stack_list ~unwind s))
+               )
+            | None ->
+               let t' = unwind k e ens t in 
+                if s = [] then t' else
+                 C.Appl (t'::(RS.from_stack_list ~unwind s))
+          )
+     | (k, e, ens, (C.CoFix (i,fl) as t),s) ->
+        let t' = unwind k e ens t in 
+         if s = [] then t' else C.Appl (t'::(RS.from_stack_list ~unwind s))
+   and push_exp_named_subst k e ens =
+    function
+       [] -> ens
+     | (uri,t)::tl ->
+         push_exp_named_subst k e ((uri,RS.to_ens (unwind k e ens t))::ens) tl
+   in
+    reduce
+  ;;
+  
+  let rec whd context t = reduce context (0, [], [], t, []);;
+  
 (* DEBUGGING ONLY
 let whd context t =
  let res = whd context t in
@@ -481,7 +748,26 @@ let _ =  CicReductionNaif.are_convertible context res rescsc in
    res
 ;;
 *)
+ end
+;;
+
+
+(*
+module R = Reduction CallByNameStrategy;;
+module R = Reduction CallByValueStrategy;;
+module R = Reduction CallByValueStrategyByNameOnConstants;;
+module R = Reduction LazyCallByValueStrategy;;
+module R = Reduction LazyCallByValueStrategyByNameOnConstants;;
+module R = Reduction LazyCallByNameStrategy;;
+module R = Reduction
+ LazyCallByValueByNameOnConstantsWhenFromStack_ByNameStrategyWhenFromEnvOrEns;;
+module R = Reduction ClosuresOnStackByValueFromEnvOrEnsStrategy;;
+module R = Reduction
+ ClosuresOnStackByValueFromEnvOrEnsByNameOnConstantsStrategy;;
+*)
+module R = Reduction ClosuresOnStackByValueFromEnvOrEnsStrategy;;
 
+let whd = R.whd;;
 
 (* t1, t2 must be well-typed *)
 let are_convertible =