]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/cic_proof_checking/cicReduction.ml
Preparing for 0.5.9 release.
[helm.git] / helm / software / components / cic_proof_checking / cicReduction.ml
1 (* Copyright (C) 2000, HELM Team.
2  * 
3  * This file is part of HELM, an Hypertextual, Electronic
4  * Library of Mathematics, developed at the Computer Science
5  * Department, University of Bologna, Italy.
6  * 
7  * HELM is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * 
12  * HELM is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with HELM; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA  02111-1307, USA.
21  * 
22  * For details, see the HELM World-Wide-Web page,
23  * http://cs.unibo.it/helm/.
24  *)
25
26 (* $Id$ *)
27
28 (* TODO unify exceptions *)
29
30 exception WrongUriToInductiveDefinition;;
31 exception Impossible of int;;
32 exception ReferenceToConstant;;
33 exception ReferenceToVariable;;
34 exception ReferenceToCurrentProof;;
35 exception ReferenceToInductiveDefinition;;
36
37 let ndebug = ref false;;
38 let indent = ref "";;
39 let times = ref [];;
40 let pp s =
41  if !ndebug then
42   prerr_endline (Printf.sprintf "%-20s" !indent ^ " " ^ Lazy.force s)
43 ;;
44 let inside c =
45  if !ndebug then
46   begin
47    let time1 = Unix.gettimeofday () in
48    indent := !indent ^ String.make 1 c;
49    times := time1 :: !times;
50    prerr_endline ("{{{" ^ !indent ^ " ")
51   end
52 ;;
53 let outside ok =
54  if !ndebug then
55   begin
56    let time2 = Unix.gettimeofday () in
57    let time1 =
58     match !times with time1::tl -> times := tl; time1 | [] -> assert false in
59    prerr_endline ("}}} " ^ string_of_float (time2 -. time1));
60    if not ok then prerr_endline "exception raised!";
61    try
62     indent := String.sub !indent 0 (String.length !indent -1)
63    with
64     Invalid_argument _ -> indent := "??"; ()
65  end
66 ;;
67
68 let debug = false
69 let profile = false
70 let debug_print s = if debug then prerr_endline (Lazy.force s)
71
72 let fdebug = ref 1;;
73 let debug t env s =
74  let rec debug_aux t i =
75   let module C = Cic in
76   let module U = UriManager in
77    CicPp.ppobj (C.Variable ("DEBUG", None, t, [], [])) ^ "\n" ^ i
78  in
79   if !fdebug = 0 then
80    debug_print (lazy (s ^ "\n" ^ List.fold_right debug_aux (t::env) ""))
81 ;;
82
83 module type Strategy =
84  sig
85   type stack_term
86   type env_term
87   type ens_term
88   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
89   val to_env :
90    reduce: (config -> config) ->
91    unwind: (config -> Cic.term) ->
92    config -> env_term
93   val to_ens :
94    reduce: (config -> config) ->
95    unwind: (config -> Cic.term) ->
96    config -> ens_term
97   val from_stack : stack_term -> config
98   val from_stack_list_for_unwind :
99    unwind: (config -> Cic.term) ->
100    stack_term list -> Cic.term list
101   val from_env : env_term -> config
102   val from_env_for_unwind :
103    unwind: (config -> Cic.term) ->
104    env_term -> Cic.term
105   val from_ens : ens_term -> config
106   val from_ens_for_unwind :
107    unwind: (config -> Cic.term) ->
108    ens_term -> Cic.term
109   val stack_to_env :
110    reduce: (config -> config) ->
111    unwind: (config -> Cic.term) ->
112    stack_term -> env_term
113   val compute_to_env :
114    reduce: (config -> config) ->
115    unwind: (config -> Cic.term) ->
116    int -> env_term list -> ens_term Cic.explicit_named_substitution ->
117     Cic.term -> env_term
118   val compute_to_stack :
119    reduce: (config -> config) ->
120    unwind: (config -> Cic.term) ->
121    config -> stack_term
122  end
123 ;;
124
125 module CallByValueByNameForUnwind =
126  struct
127   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
128   and stack_term = config
129   and env_term = config * config (* cbv, cbn *)
130   and ens_term = config * config (* cbv, cbn *)
131
132   let to_env c = c,c
133   let to_ens c = c,c
134   let from_stack config = config
135   let from_stack_list_for_unwind ~unwind l = List.map unwind l
136   let from_env (c,_) = c
137   let from_ens (c,_) = c
138   let from_env_for_unwind ~unwind (_,c) = unwind c
139   let from_ens_for_unwind ~unwind (_,c) = unwind c
140   let stack_to_env ~reduce ~unwind config = reduce config, (0,[],[],unwind config,[])
141   let compute_to_env ~reduce ~unwind k e ens t = (k,e,ens,t,[]), (k,e,ens,t,[])
142   let compute_to_stack ~reduce ~unwind config = config
143  end
144 ;;
145
146 module CallByValueByNameForUnwind' =
147  struct
148   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
149   and stack_term = config lazy_t * Cic.term lazy_t (* cbv, cbn *)
150   and env_term = config lazy_t * Cic.term lazy_t (* cbv, cbn *)
151   and ens_term = config lazy_t * Cic.term lazy_t (* cbv, cbn *)
152
153   let to_env ~reduce ~unwind c = lazy (reduce c),lazy (unwind c)
154   let to_ens ~reduce ~unwind c = lazy (reduce c),lazy (unwind c)
155   let from_stack (c,_) = Lazy.force c
156   let from_stack_list_for_unwind ~unwind l = List.map (function (_,c) -> Lazy.force c) l
157   let from_env (c,_) = Lazy.force c
158   let from_ens (c,_) = Lazy.force c
159   let from_env_for_unwind ~unwind (_,c) = Lazy.force c
160   let from_ens_for_unwind ~unwind (_,c) = Lazy.force c
161   let stack_to_env ~reduce ~unwind config = config
162   let compute_to_env ~reduce ~unwind k e ens t =
163    lazy (reduce (k,e,ens,t,[])), lazy (unwind (k,e,ens,t,[]))
164   let compute_to_stack ~reduce ~unwind config = lazy (reduce config), lazy (unwind config)
165  end
166 ;;
167
168
169 (* Old Machine
170 module CallByNameStrategy =
171  struct
172   type stack_term = Cic.term
173   type env_term = Cic.term
174   type ens_term = Cic.term
175   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
176   let to_env v = v
177   let to_ens v = v
178   let from_stack ~unwind v = v
179   let from_stack_list ~unwind l = l
180   let from_env v = v
181   let from_ens v = v
182   let from_env_for_unwind ~unwind v = v
183   let from_ens_for_unwind ~unwind v = v
184   let stack_to_env ~reduce ~unwind v = v
185   let compute_to_stack ~reduce ~unwind k e ens t = unwind k e ens t
186   let compute_to_env ~reduce ~unwind k e ens t = unwind k e ens t
187  end
188 ;;
189 *)
190
191 module CallByNameStrategy =
192  struct
193   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
194   and stack_term = config
195   and env_term = config
196   and ens_term = config
197
198   let to_env c = c
199   let to_ens c = c
200   let from_stack config = config
201   let from_stack_list_for_unwind ~unwind l = List.map unwind l
202   let from_env c = c
203   let from_ens c = c
204   let from_env_for_unwind ~unwind c = unwind c
205   let from_ens_for_unwind ~unwind c = unwind c
206   let stack_to_env ~reduce ~unwind config = 0,[],[],unwind config,[]
207   let compute_to_env ~reduce ~unwind k e ens t = k,e,ens,t,[]
208   let compute_to_stack ~reduce ~unwind config = config
209  end
210 ;;
211
212 module CallByValueStrategy =
213  struct
214   type stack_term = Cic.term
215   type env_term = Cic.term
216   type ens_term = Cic.term
217   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
218   let to_env v = v
219   let to_ens v = v
220   let from_stack ~unwind v = v
221   let from_stack_list ~unwind l = l
222   let from_env v = v
223   let from_ens v = v
224   let from_env_for_unwind ~unwind v = v
225   let from_ens_for_unwind ~unwind v = v
226   let stack_to_env ~reduce ~unwind v = v
227   let compute_to_stack ~reduce ~unwind k e ens t = reduce (k,e,ens,t,[])
228   let compute_to_env ~reduce ~unwind k e ens t = reduce (k,e,ens,t,[])
229  end
230 ;;
231
232 module CallByValueStrategyByNameOnConstants =
233  struct
234   type stack_term = Cic.term
235   type env_term = Cic.term
236   type ens_term = Cic.term
237   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
238   let to_env v = v
239   let to_ens v = v
240   let from_stack ~unwind v = v
241   let from_stack_list ~unwind l = l
242   let from_env v = v
243   let from_ens v = v
244   let from_env_for_unwind ~unwind v = v
245   let from_ens_for_unwind ~unwind v = v
246   let stack_to_env ~reduce ~unwind v = v
247   let compute_to_stack ~reduce ~unwind k e ens =
248    function
249       Cic.Const _ as t -> unwind k e ens t    
250     | t -> reduce (k,e,ens,t,[])
251   let compute_to_env ~reduce ~unwind k e ens =
252    function
253       Cic.Const _ as t -> unwind k e ens t    
254     | t -> reduce (k,e,ens,t,[])
255  end
256 ;;
257
258 module LazyCallByValueStrategy =
259  struct
260   type stack_term = Cic.term lazy_t
261   type env_term = Cic.term lazy_t
262   type ens_term = Cic.term lazy_t
263   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
264   let to_env v = lazy v
265   let to_ens v = lazy v
266   let from_stack ~unwind v = Lazy.force v
267   let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
268   let from_env v = Lazy.force v
269   let from_ens v = Lazy.force v
270   let from_env_for_unwind ~unwind v = Lazy.force v
271   let from_ens_for_unwind ~unwind v = Lazy.force v
272   let stack_to_env ~reduce ~unwind v = v
273   let compute_to_stack ~reduce ~unwind k e ens t = lazy (reduce (k,e,ens,t,[]))
274   let compute_to_env ~reduce ~unwind k e ens t = lazy (reduce (k,e,ens,t,[]))
275  end
276 ;;
277
278 module LazyCallByValueStrategyByNameOnConstants =
279  struct
280   type stack_term = Cic.term lazy_t
281   type env_term = Cic.term lazy_t
282   type ens_term = Cic.term lazy_t
283   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
284   let to_env v = lazy v
285   let to_ens v = lazy v
286   let from_stack ~unwind v = Lazy.force v
287   let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
288   let from_env v = Lazy.force v
289   let from_ens v = Lazy.force v
290   let from_env_for_unwind ~unwind v = Lazy.force v
291   let from_ens_for_unwind ~unwind v = Lazy.force v
292   let stack_to_env ~reduce ~unwind v = v
293   let compute_to_stack ~reduce ~unwind k e ens t =
294    lazy (
295     match t with
296        Cic.Const _ as t -> unwind k e ens t    
297      | t -> reduce (k,e,ens,t,[]))
298   let compute_to_env ~reduce ~unwind k e ens t =
299    lazy (
300     match t with
301        Cic.Const _ as t -> unwind k e ens t    
302      | t -> reduce (k,e,ens,t,[]))
303  end
304 ;;
305
306 module LazyCallByNameStrategy =
307  struct
308   type stack_term = Cic.term lazy_t
309   type env_term = Cic.term lazy_t
310   type ens_term = Cic.term lazy_t
311   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
312   let to_env v = lazy v
313   let to_ens v = lazy v
314   let from_stack ~unwind v = Lazy.force v
315   let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
316   let from_env v = Lazy.force v
317   let from_ens v = Lazy.force v
318   let from_env_for_unwind ~unwind v = Lazy.force v
319   let from_ens_for_unwind ~unwind v = Lazy.force v
320   let stack_to_env ~reduce ~unwind v = v
321   let compute_to_stack ~reduce ~unwind k e ens t = lazy (unwind k e ens t)
322   let compute_to_env ~reduce ~unwind k e ens t = lazy (unwind k e ens t)
323  end
324 ;;
325
326 module
327  LazyCallByValueByNameOnConstantsWhenFromStack_ByNameStrategyWhenFromEnvOrEns
328 =
329  struct
330   type stack_term = reduce:bool -> Cic.term
331   type env_term = reduce:bool -> Cic.term
332   type ens_term = reduce:bool -> Cic.term
333   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
334   let to_env v =
335    let value = lazy v in
336     fun ~reduce -> Lazy.force value
337   let to_ens v =
338    let value = lazy v in
339     fun ~reduce -> Lazy.force value
340   let from_stack ~unwind v = (v ~reduce:false)
341   let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
342   let from_env v = (v ~reduce:true)
343   let from_ens v = (v ~reduce:true)
344   let from_env_for_unwind ~unwind v = (v ~reduce:true)
345   let from_ens_for_unwind ~unwind v = (v ~reduce:true)
346   let stack_to_env ~reduce ~unwind v = v
347   let compute_to_stack ~reduce ~unwind k e ens t =
348    let svalue =
349      lazy (
350       match t with
351          Cic.Const _ as t -> unwind k e ens t    
352        | t -> reduce (k,e,ens,t,[])
353      ) in
354    let lvalue =
355     lazy (unwind k e ens t)
356    in
357     fun ~reduce ->
358      if reduce then Lazy.force svalue else Lazy.force lvalue
359   let compute_to_env ~reduce ~unwind k e ens t =
360    let svalue =
361      lazy (
362       match t with
363          Cic.Const _ as t -> unwind k e ens t    
364        | t -> reduce (k,e,ens,t,[])
365      ) in
366    let lvalue =
367     lazy (unwind k e ens t)
368    in
369     fun ~reduce ->
370      if reduce then Lazy.force svalue else Lazy.force lvalue
371  end
372 ;;
373
374 module ClosuresOnStackByValueFromEnvOrEnsStrategy =
375  struct
376   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
377   and stack_term = config
378   and env_term = config
379   and ens_term = config
380
381   let to_env config = config
382   let to_ens config = config
383   let from_stack config = config
384   let from_stack_list_for_unwind ~unwind l = List.map unwind l
385   let from_env v = v
386   let from_ens v = v
387   let from_env_for_unwind ~unwind config = unwind config
388   let from_ens_for_unwind ~unwind config = unwind config
389   let stack_to_env ~reduce ~unwind config = reduce config
390   let compute_to_env ~reduce ~unwind k e ens t = (k,e,ens,t,[])
391   let compute_to_stack ~reduce ~unwind config = config
392  end
393 ;;
394
395 module ClosuresOnStackByValueFromEnvOrEnsByNameOnConstantsStrategy =
396  struct
397   type stack_term =
398    int * Cic.term list * Cic.term Cic.explicit_named_substitution * Cic.term
399   type env_term = Cic.term
400   type ens_term = Cic.term
401   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
402   let to_env v = v
403   let to_ens v = v
404   let from_stack ~unwind (k,e,ens,t) = unwind k e ens t
405   let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
406   let from_env v = v
407   let from_ens v = v
408   let from_env_for_unwind ~unwind v = v
409   let from_ens_for_unwind ~unwind v = v
410   let stack_to_env ~reduce ~unwind (k,e,ens,t) =
411    match t with
412       Cic.Const _ as t -> unwind k e ens t    
413     | t -> reduce (k,e,ens,t,[])
414   let compute_to_env ~reduce ~unwind k e ens t =
415    unwind k e ens t
416   let compute_to_stack ~reduce ~unwind k e ens t = (k,e,ens,t)
417  end
418 ;;
419
420 module Reduction(RS : Strategy) =
421  struct
422   type env = RS.env_term list
423   type ens = RS.ens_term Cic.explicit_named_substitution
424   type stack = RS.stack_term list
425   type config = int * env * ens * Cic.term * stack
426
427   (* k is the length of the environment e *)
428   (* m is the current depth inside the term *)
429   let rec unwind' m k e ens t = 
430    let module C = Cic in
431    let module S = CicSubstitution in
432     if k = 0 && ens = [] then
433      t
434     else 
435      let rec unwind_aux m =
436       function
437          C.Rel n as t ->
438           if n <= m then t else
439            let d =
440             try
441              Some (RS.from_env_for_unwind ~unwind (List.nth e (n-m-1)))
442             with Failure _ -> None
443            in
444             (match d with 
445                 Some t' ->
446                  if m = 0 then t' else S.lift m t'
447               | None -> C.Rel (n-k)
448             )
449        | C.Var (uri,exp_named_subst) ->
450 (*
451 debug_print (lazy ("%%%%%UWVAR " ^ String.concat " ; " (List.map (function (uri,t) -> UriManager.string_of_uri uri ^ " := " ^ CicPp.ppterm t) ens))) ;
452 *)
453          if List.exists (function (uri',_) -> UriManager.eq uri' uri) ens then
454           CicSubstitution.lift m (RS.from_ens_for_unwind ~unwind (List.assq uri ens))
455          else
456           let params =
457             let o,_ = 
458               CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
459             in
460            (match o with
461                C.Constant _ -> raise ReferenceToConstant
462              | C.Variable (_,_,_,params,_) -> params
463              | C.CurrentProof _ -> raise ReferenceToCurrentProof
464              | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
465            )
466           in
467            let exp_named_subst' =
468             substaux_in_exp_named_subst params exp_named_subst m 
469            in
470             C.Var (uri,exp_named_subst')
471        | C.Meta (i,l) ->
472           let l' =
473            List.map
474             (function
475                 None -> None
476               | Some t -> Some (unwind_aux m t)
477             ) l
478           in
479            C.Meta (i, l')
480        | C.Sort _ as t -> t
481        | C.Implicit _ as t -> t
482        | C.Cast (te,ty) -> C.Cast (unwind_aux m te, unwind_aux m ty) (*CSC ???*)
483        | C.Prod (n,s,t) -> C.Prod (n, unwind_aux m s, unwind_aux (m + 1) t)
484        | C.Lambda (n,s,t) -> C.Lambda (n, unwind_aux m s, unwind_aux (m + 1) t)
485        | C.LetIn (n,s,ty,t) ->
486           C.LetIn (n, unwind_aux m s, unwind_aux m ty, unwind_aux (m + 1) t)
487        | C.Appl l -> C.Appl (List.map (unwind_aux m) l)
488        | C.Const (uri,exp_named_subst) ->
489           let params =
490             let o,_ = 
491               CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
492             in
493            (match o with
494                C.Constant (_,_,_,params,_) -> params
495              | C.Variable _ -> raise ReferenceToVariable
496              | C.CurrentProof (_,_,_,_,params,_) -> params
497              | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
498            )
499           in
500            let exp_named_subst' =
501             substaux_in_exp_named_subst params exp_named_subst m 
502            in
503             C.Const (uri,exp_named_subst')
504        | C.MutInd (uri,i,exp_named_subst) ->
505           let params =
506             let o,_ = 
507               CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
508             in
509            (match o with
510                C.Constant _ -> raise ReferenceToConstant
511              | C.Variable _ -> raise ReferenceToVariable
512              | C.CurrentProof _ -> raise ReferenceToCurrentProof
513              | C.InductiveDefinition (_,params,_,_) -> params
514            )
515           in
516            let exp_named_subst' =
517             substaux_in_exp_named_subst params exp_named_subst m 
518            in
519             C.MutInd (uri,i,exp_named_subst')
520        | C.MutConstruct (uri,i,j,exp_named_subst) ->
521           let params =
522             let o,_ = 
523               CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
524             in
525            (match o with
526                C.Constant _ -> raise ReferenceToConstant
527              | C.Variable _ -> raise ReferenceToVariable
528              | C.CurrentProof _ -> raise ReferenceToCurrentProof
529              | C.InductiveDefinition (_,params,_,_) -> params
530            )
531           in
532            let exp_named_subst' =
533             substaux_in_exp_named_subst params exp_named_subst m 
534            in
535             C.MutConstruct (uri,i,j,exp_named_subst')
536        | C.MutCase (sp,i,outt,t,pl) ->
537           C.MutCase (sp,i,unwind_aux m outt, unwind_aux m t,
538            List.map (unwind_aux m) pl)
539        | C.Fix (i,fl) ->
540           let len = List.length fl in
541           let substitutedfl =
542            List.map
543             (fun (name,i,ty,bo) ->
544               (name, i, unwind_aux m ty, unwind_aux (m+len) bo))
545              fl
546           in
547            C.Fix (i, substitutedfl)
548        | C.CoFix (i,fl) ->
549           let len = List.length fl in
550           let substitutedfl =
551            List.map
552             (fun (name,ty,bo) -> (name, unwind_aux m ty, unwind_aux (m+len) bo))
553              fl
554           in
555            C.CoFix (i, substitutedfl)
556      and substaux_in_exp_named_subst params exp_named_subst' m  =
557      (*CSC: codice copiato e modificato dalla cicSubstitution.subst_vars *)
558       let rec filter_and_lift already_instantiated =
559        function
560           [] -> []
561         | (uri,t)::tl when
562             List.for_all
563              (function (uri',_)-> not (UriManager.eq uri uri')) exp_named_subst'
564             &&
565              not (List.mem uri already_instantiated)
566             &&
567              List.mem uri params
568            ->
569             (uri,CicSubstitution.lift m (RS.from_ens_for_unwind ~unwind t)) ::
570              (filter_and_lift (uri::already_instantiated) tl)
571         | _::tl -> filter_and_lift already_instantiated tl
572       in
573        let res =
574         List.map (function (uri,t) -> uri, unwind_aux m t) exp_named_subst' @
575          (filter_and_lift [] (List.rev ens))
576        in
577         let rec reorder =
578          function
579             [] -> []
580           | uri::tl ->
581              let he =
582               try
583                [uri,List.assoc uri res]
584               with
585                Not_found -> []
586              in
587               he@reorder tl
588         in
589          reorder params
590      in
591       unwind_aux m t          
592   
593   and unwind (k,e,ens,t,s) =
594    let t' = unwind' 0 k e ens t in
595     if s = [] then t' else Cic.Appl (t'::(RS.from_stack_list_for_unwind ~unwind s))
596   ;;
597
598 (*
599   let unwind =
600    let profiler_unwind = HExtlib.profile ~enable:profile "are_convertible.unwind" in
601     fun k e ens t ->
602      profiler_unwind.HExtlib.profile (unwind k e ens) t
603   ;;
604 *)
605   
606   let reduce ~delta ?(subst = []) context : config -> config = 
607    let module C = Cic in
608    let module S = CicSubstitution in 
609    let rec reduce =
610     function
611        (k, e, _, C.Rel n, s) as config ->
612         let config' =
613          if not delta then None
614          else
615           try
616            Some (RS.from_env (List.nth e (n-1)))
617           with
618            Failure _ ->
619             try
620              begin
621               match List.nth context (n - 1 - k) with
622                  None -> assert false
623                | Some (_,C.Decl _) -> None
624                | Some (_,C.Def (x,_)) -> Some (0,[],[],S.lift (n - k) x,[])
625              end
626             with
627              Failure _ -> None
628         in
629          (match config' with 
630              Some (k',e',ens',t',s') -> reduce (k',e',ens',t',s'@s)
631            | None -> config)
632      | (k, e, ens, C.Var (uri,exp_named_subst), s) as config -> 
633          if List.exists (function (uri',_) -> UriManager.eq uri' uri) ens then
634           let (k',e',ens',t',s') = RS.from_ens (List.assq uri ens) in
635            reduce (k',e',ens',t',s'@s)
636          else
637           ( let o,_ = 
638               CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
639             in
640             match o with
641               C.Constant _ -> raise ReferenceToConstant
642             | C.CurrentProof _ -> raise ReferenceToCurrentProof
643             | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
644             | C.Variable (_,None,_,_,_) -> config
645             | C.Variable (_,Some body,_,_,_) ->
646                let ens' = push_exp_named_subst k e ens exp_named_subst in
647                 reduce (0, [], ens', body, s)
648           )
649      | (k, e, ens, C.Meta (n,l), s) as config ->
650         (try 
651            let (_, term,_) = CicUtil.lookup_subst n subst in
652            reduce (k, e, ens,CicSubstitution.subst_meta l term,s)
653          with  CicUtil.Subst_not_found _ -> config)
654      | (_, _, _, C.Sort _, _)
655      | (_, _, _, C.Implicit _, _) as config -> config
656      | (k, e, ens, C.Cast (te,ty), s) ->
657         reduce (k, e, ens, te, s)
658      | (_, _, _, C.Prod _, _) as config -> config
659      | (_, _, _, C.Lambda _, []) as config -> config
660      | (k, e, ens, C.Lambda (_,_,t), p::s) ->
661          reduce (k+1, (RS.stack_to_env ~reduce ~unwind p)::e, ens, t,s)
662      | (k, e, ens, C.LetIn (_,m,_,t), s) ->
663         let m' = RS.compute_to_env ~reduce ~unwind k e ens m in
664          reduce (k+1, m'::e, ens, t, s)
665      | (_, _, _, C.Appl [], _) -> assert false
666      | (k, e, ens, C.Appl (he::tl), s) ->
667         let tl' =
668          List.map
669           (function t -> RS.compute_to_stack ~reduce ~unwind (k,e,ens,t,[])) tl
670         in
671          reduce (k, e, ens, he, (List.append tl') s)
672      | (_, _, _, C.Const _, _) as config when delta=false-> config
673      | (k, e, ens, C.Const (uri,exp_named_subst), s) as config ->
674         (let o,_ = 
675            CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
676          in
677           match o with
678             C.Constant (_,Some body,_,_,_) ->
679              let ens' = push_exp_named_subst k e ens exp_named_subst in
680               (* constants are closed *)
681               reduce (0, [], ens', body, s) 
682           | C.Constant (_,None,_,_,_) -> config
683           | C.Variable _ -> raise ReferenceToVariable
684           | C.CurrentProof (_,_,body,_,_,_) ->
685              let ens' = push_exp_named_subst k e ens exp_named_subst in
686               (* constants are closed *)
687               reduce (0, [], ens', body, s)
688           | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
689         )
690      | (_, _, _, C.MutInd _, _)
691      | (_, _, _, C.MutConstruct _, _) as config -> config 
692      | (k, e, ens, C.MutCase (mutind,i,outty,term,pl),s) as config ->
693         let decofix =
694          function
695             (k, e, ens, C.CoFix (i,fl), s) ->
696              let (_,_,body) = List.nth fl i in
697               let body' =
698                let counter = ref (List.length fl) in
699                 List.fold_right
700                  (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
701                  fl
702                  body
703               in
704                reduce (k,e,ens,body',s)
705           | config -> config
706         in
707          (match decofix (reduce (k,e,ens,term,[])) with
708              (k', e', ens', C.MutConstruct (_,_,j,_), []) ->
709               reduce (k, e, ens, (List.nth pl (j-1)), s)
710            | (k', e', ens', C.MutConstruct (_,_,j,_), s') ->
711               let r =
712                 let o,_ = 
713                   CicEnvironment.get_cooked_obj CicUniv.empty_ugraph mutind 
714                 in
715                   match o with
716                       C.InductiveDefinition (_,_,r,_) -> r
717                     | _ -> raise WrongUriToInductiveDefinition
718               in
719                let ts =
720                 let num_to_eat = r in
721                  let rec eat_first =
722                   function
723                      (0,l) -> l
724                    | (n,he::s) when n > 0 -> eat_first (n - 1, s)
725                    | _ -> raise (Impossible 5)
726                  in
727                   eat_first (num_to_eat,s')
728                in
729                 reduce (k, e, ens, (List.nth pl (j-1)), ts@s)
730            | (_, _, _, C.Cast _, _)
731            | (_, _, _, C.Implicit _, _) ->
732               raise (Impossible 2) (* we don't trust our whd ;-) *)
733            | config' ->
734               (*CSC: here I am unwinding the configuration and for sure I
735                 will do it twice; to avoid this unwinding I should push the
736                 "match [] with _" continuation on the stack;
737                 another possibility is to just return the original configuration,
738                 partially undoing the weak-head computation *)
739               (*this code is uncorrect since term' lives in e' <> e
740               let term' = unwind config' in
741                (k, e, ens, C.MutCase (mutind,i,outty,term',pl),s)
742               *)
743               config)
744      | (k, e, ens, C.Fix (i,fl), s) as config ->
745         let (_,recindex,_,body) = List.nth fl i in
746          let recparam =
747           try
748            Some (RS.from_stack (List.nth s recindex))
749           with
750            Failure _ -> None
751          in
752           (match recparam with
753               Some recparam ->
754                (match reduce recparam with
755                    (_,_,_,C.MutConstruct _,_) as config ->
756                     let leng = List.length fl in
757                     let new_env =
758                      let counter = ref 0 in
759                      let rec build_env e' =
760                       if !counter = leng then e'
761                       else
762                        (incr counter ;
763                         build_env
764                          ((RS.to_env ~reduce ~unwind (k,e,ens,C.Fix (!counter -1, fl),[]))::e'))
765                      in
766                       build_env e
767                     in
768                     let rec replace i s t =
769                      match i,s with
770                         0,_::tl -> t::tl
771                       | n,he::tl -> he::(replace (n - 1) tl t)
772                       | _,_ -> assert false in
773                     let new_s =
774                      replace recindex s (RS.compute_to_stack ~reduce ~unwind config)
775                     in
776                      reduce (k+leng, new_env, ens, body, new_s)
777                  | _ -> config)
778             | None -> config
779           )
780      | (_,_,_,C.CoFix _,_) as config -> config
781    and push_exp_named_subst k e ens =
782     function
783        [] -> ens
784      | (uri,t)::tl ->
785          push_exp_named_subst k e ((uri,RS.to_ens ~reduce ~unwind (k,e,ens,t,[]))::ens) tl
786    in
787     reduce
788   ;;
789
790   let whd ?(delta=true) ?(subst=[]) context t = 
791    unwind (reduce ~delta ~subst context (0, [], [], t, []))
792   ;;
793
794  end
795 ;;
796
797
798 (* ROTTO = rompe l'unificazione poiche' riduce gli argomenti di un'applicazione
799            senza ridurre la testa
800 module R = Reduction CallByNameStrategy;; OK 56.368s
801 module R = Reduction CallByValueStrategy;; ROTTO
802 module R = Reduction CallByValueStrategyByNameOnConstants;; ROTTO
803 module R = Reduction LazyCallByValueStrategy;; ROTTO
804 module R = Reduction LazyCallByValueStrategyByNameOnConstants;; ROTTO
805 module R = Reduction LazyCallByNameStrategy;; OK 0m56.398s
806 module R = Reduction
807  LazyCallByValueByNameOnConstantsWhenFromStack_ByNameStrategyWhenFromEnvOrEns;;
808  OK 59.058s
809 module R = Reduction ClosuresOnStackByValueFromEnvOrEnsStrategy;; OK 58.583s
810 module R = Reduction
811  ClosuresOnStackByValueFromEnvOrEnsByNameOnConstantsStrategy;; OK 58.094s
812 module R = Reduction(ClosuresOnStackByValueFromEnvOrEnsStrategy);; OK 58.127s
813 *)
814 (*module R = Reduction(CallByValueByNameForUnwind);;*)
815 module RS = CallByValueByNameForUnwind';;
816 (*module R = Reduction(CallByNameStrategy);;*)
817 (*module R = Reduction(ClosuresOnStackByValueFromEnvOrEnsStrategy);;*)
818 module R = Reduction(RS);;
819 module U = UriManager;;
820
821 let whd = R.whd
822
823 (*
824 let whd =
825  let profiler_whd = HExtlib.profile ~enable:profile "are_convertible.whd" in
826   fun ?(delta=true) ?(subst=[]) context t ->
827    profiler_whd.HExtlib.profile (whd ~delta ~subst context) t
828 *)
829
830   (* mimic ocaml (<< 3.08) "=" behaviour. Tests physical equality first then
831     * fallbacks to structural equality *)
832 let (===) x y =
833   Pervasives.compare x y = 0
834
835 (* t1, t2 must be well-typed *)
836 let are_convertible whd ?(subst=[]) ?(metasenv=[])  =
837  let heuristic = ref true in
838  let rec aux test_equality_only context t1 t2 ugraph =
839  (*D*)inside 'B'; try let rc = 
840   pp (lazy (CicPp.ppterm t1 ^ " vs " ^ CicPp.ppterm t2));
841   let rec aux2 test_equality_only t1 t2 ugraph =
842
843    (* this trivial euristic cuts down the total time of about five times ;-) *)
844    (* this because most of the time t1 and t2 are "sintactically" the same   *)
845    if t1 === t2 then
846      true,ugraph
847    else
848     begin
849      let module C = Cic in
850        match (t1,t2) with
851           (C.Rel n1, C.Rel n2) -> (n1 = n2),ugraph
852         | (C.Var (uri1,exp_named_subst1), C.Var (uri2,exp_named_subst2)) ->
853             if U.eq uri1 uri2 then
854              (try
855                List.fold_right2
856                 (fun (uri1,x) (uri2,y) (b,ugraph) ->
857                   let b',ugraph' = aux test_equality_only context x y ugraph in
858                   (U.eq uri1 uri2 && b' && b),ugraph'
859                 ) exp_named_subst1 exp_named_subst2 (true,ugraph) 
860               with
861                Invalid_argument _ -> false,ugraph
862              )
863             else
864               false,ugraph
865         | (C.Meta (n1,l1), C.Meta (n2,l2)) ->
866             if n1 = n2 then
867               let b2, ugraph1 = 
868                 let l1 = CicUtil.clean_up_local_context subst metasenv n1 l1 in
869                 let l2 = CicUtil.clean_up_local_context subst metasenv n2 l2 in
870                   List.fold_left2
871                     (fun (b,ugraph) t1 t2 ->
872                        if b then 
873                          match t1,t2 with
874                              None,_
875                            | _,None  -> true,ugraph
876                            | Some t1',Some t2' -> 
877                                aux test_equality_only context t1' t2' ugraph
878                        else
879                          false,ugraph
880                     ) (true,ugraph) l1 l2
881               in
882                 if b2 then true,ugraph1 else false,ugraph 
883             else
884               false,ugraph
885         | C.Meta (n1,l1), _ ->
886            (try 
887               let _,term,_ = CicUtil.lookup_subst n1 subst in
888               let term' = CicSubstitution.subst_meta l1 term in
889 (*
890 prerr_endline ("%?: " ^ CicPp.ppterm t1 ^ " <==> " ^ CicPp.ppterm t2);
891 prerr_endline ("%%%%%%: " ^ CicPp.ppterm term' ^ " <==> " ^ CicPp.ppterm t2);
892 *)
893                aux test_equality_only context term' t2 ugraph
894             with  CicUtil.Subst_not_found _ -> false,ugraph)
895         | _, C.Meta (n2,l2) ->
896            (try 
897               let _,term,_ = CicUtil.lookup_subst n2 subst in
898               let term' = CicSubstitution.subst_meta l2 term in
899 (*
900 prerr_endline ("%?: " ^ CicPp.ppterm t1 ^ " <==> " ^ CicPp.ppterm t2);
901 prerr_endline ("%%%%%%: " ^ CicPp.ppterm term' ^ " <==> " ^ CicPp.ppterm t1);
902 *)
903                aux test_equality_only context t1 term' ugraph
904             with  CicUtil.Subst_not_found _ -> false,ugraph)
905         | (C.Sort (C.CProp t1|C.Type t1), C.Sort (C.CProp t2|C.Type t2)) 
906           when test_equality_only ->
907             (try true,(CicUniv.add_eq t2 t1 ugraph)
908             with CicUniv.UniverseInconsistency _ -> false,ugraph)
909         | (C.Sort (C.CProp t1|C.Type t1), C.Sort (C.CProp t2|C.Type t2))
910           when not test_equality_only ->
911             (try true,(CicUniv.add_ge t2 t1 ugraph)
912             with CicUniv.UniverseInconsistency _ -> false,ugraph)
913         | (C.Sort s1, C.Sort (C.Type _))
914         | (C.Sort s1, C.Sort (C.CProp _)) -> (not test_equality_only),ugraph
915         | (C.Sort s1, C.Sort s2) -> (s1 = s2),ugraph
916         | (C.Prod (name1,s1,t1), C.Prod(_,s2,t2)) ->
917             let b',ugraph' = aux true context s1 s2 ugraph in
918             if b' then 
919               aux test_equality_only ((Some (name1, (C.Decl s1)))::context) 
920                 t1 t2 ugraph'
921             else
922               false,ugraph
923         | (C.Lambda (name1,s1,t1), C.Lambda(_,s2,t2)) ->
924            let b',ugraph' = aux true context s1 s2 ugraph in
925            if b' then
926              aux test_equality_only ((Some (name1, (C.Decl s1)))::context) 
927                t1 t2 ugraph'
928            else
929              false,ugraph
930         | (C.LetIn (name1,s1,ty1,t1), C.LetIn(_,s2,ty2,t2)) ->
931            let b',ugraph' = aux test_equality_only context s1 s2 ugraph in
932            if b' then
933             let b',ugraph = aux test_equality_only context ty1 ty2 ugraph in
934             if b' then
935              aux test_equality_only
936               ((Some (name1, (C.Def (s1,ty1))))::context) t1 t2 ugraph'
937             else
938               false,ugraph
939            else
940              false,ugraph
941         | (C.Appl l1, C.Appl l2) ->
942            let b, ugraph = 
943              aux test_equality_only context (List.hd l1) (List.hd l2) ugraph
944            in
945            if not b then false, ugraph
946            else
947            (try
948              List.fold_right2
949                (fun  x y (b,ugraph) -> 
950                  if b then
951                    aux true context x y ugraph
952                  else
953                    false,ugraph) (List.tl l1) (List.tl l2) (true,ugraph)
954             with
955              Invalid_argument _ -> false,ugraph
956            )
957         | (C.Const (uri1,exp_named_subst1), C.Const (uri2,exp_named_subst2)) ->
958             let b' = U.eq uri1 uri2 in
959             if b' then
960              (try
961                List.fold_right2
962                 (fun (uri1,x) (uri2,y) (b,ugraph) ->
963                   if b && U.eq uri1 uri2 then
964                     aux test_equality_only context x y ugraph 
965                   else
966                     false,ugraph
967                 ) exp_named_subst1 exp_named_subst2 (true,ugraph)
968               with
969                Invalid_argument _ -> false,ugraph
970              )
971             else
972               false,ugraph
973         | (C.MutInd (uri1,i1,exp_named_subst1),
974            C.MutInd (uri2,i2,exp_named_subst2)
975           ) ->
976             let b' = U.eq uri1 uri2 && i1 = i2 in
977             if b' then
978              (try
979                List.fold_right2
980                 (fun (uri1,x) (uri2,y) (b,ugraph) ->
981                   if b && U.eq uri1 uri2 then
982                     aux test_equality_only context x y ugraph
983                   else
984                    false,ugraph
985                 ) exp_named_subst1 exp_named_subst2 (true,ugraph)
986               with
987                Invalid_argument _ -> false,ugraph
988              )
989             else 
990               false,ugraph
991         | (C.MutConstruct (uri1,i1,j1,exp_named_subst1),
992            C.MutConstruct (uri2,i2,j2,exp_named_subst2)
993           ) ->
994             let b' = U.eq uri1 uri2 && i1 = i2 && j1 = j2 in
995             if b' then
996              (try
997                List.fold_right2
998                 (fun (uri1,x) (uri2,y) (b,ugraph) ->
999                   if b && U.eq uri1 uri2 then
1000                     aux test_equality_only context x y ugraph
1001                   else
1002                     false,ugraph
1003                 ) exp_named_subst1 exp_named_subst2 (true,ugraph)
1004               with
1005                Invalid_argument _ -> false,ugraph
1006              )
1007             else
1008               false,ugraph
1009         | (C.MutCase (uri1,i1,outtype1,term1,pl1),
1010            C.MutCase (uri2,i2,outtype2,term2,pl2)) -> 
1011             let b' = U.eq uri1 uri2 && i1 = i2 in
1012             if b' then
1013              let b'',ugraph''=aux test_equality_only context 
1014                  outtype1 outtype2 ugraph in
1015              if b'' then 
1016                let b''',ugraph'''= aux true context 
1017                    term1 term2 ugraph'' in
1018                List.fold_right2
1019                  (fun x y (b,ugraph) -> 
1020                    if b then
1021                      aux test_equality_only context x y ugraph 
1022                    else 
1023                      false,ugraph)
1024                  pl1 pl2 (b''',ugraph''')
1025              else
1026                false,ugraph
1027             else
1028               false,ugraph
1029         | (C.Fix (i1,fl1), C.Fix (i2,fl2)) ->
1030             let tys,_ =
1031               List.fold_left
1032                 (fun (types,len) (n,_,ty,_) ->
1033                    (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
1034                     len+1)
1035                 ) ([],0) fl1
1036             in
1037             if i1 = i2 then
1038              List.fold_right2
1039               (fun (_,recindex1,ty1,bo1) (_,recindex2,ty2,bo2) (b,ugraph) ->
1040                 if b && recindex1 = recindex2 then
1041                   let b',ugraph' = aux test_equality_only context ty1 ty2 
1042                       ugraph in
1043                   if b' then
1044                     aux test_equality_only (tys@context) bo1 bo2 ugraph'
1045                   else
1046                     false,ugraph
1047                 else
1048                   false,ugraph)
1049              fl1 fl2 (true,ugraph)
1050             else
1051               false,ugraph
1052         | (C.CoFix (i1,fl1), C.CoFix (i2,fl2)) ->
1053             let tys,_ =
1054               List.fold_left
1055                 (fun (types,len) (n,ty,_) ->
1056                    (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
1057                     len+1)
1058                 ) ([],0) fl1
1059             in
1060             if i1 = i2 then
1061               List.fold_right2
1062               (fun (_,ty1,bo1) (_,ty2,bo2) (b,ugraph) ->
1063                 if b then
1064                   let b',ugraph' = aux test_equality_only context ty1 ty2 
1065                       ugraph in
1066                   if b' then
1067                     aux test_equality_only (tys@context) bo1 bo2 ugraph'
1068                   else
1069                     false,ugraph
1070                 else
1071                   false,ugraph)
1072              fl1 fl2 (true,ugraph)
1073             else
1074               false,ugraph
1075         | C.Cast (bo,_),t -> aux2 test_equality_only bo t ugraph
1076         | t,C.Cast (bo,_) -> aux2 test_equality_only t bo ugraph
1077         | (C.Implicit _, _) | (_, C.Implicit _) -> assert false
1078         | (_,_) -> false,ugraph
1079     end
1080   in
1081    let res =
1082     if !heuristic then
1083      aux2 test_equality_only t1 t2 ugraph
1084     else
1085      false,ugraph
1086    in
1087     if fst res = true then
1088      res
1089     else
1090 begin
1091 (*if !heuristic then prerr_endline ("NON FACILE: " ^ CicPp.ppterm t1 ^ " <===> " ^ CicPp.ppterm t2);*)
1092    (* heuristic := false; *)
1093    debug t1 [t2] "PREWHD";
1094 (*prerr_endline ("PREWHD: " ^ CicPp.ppterm t1 ^ " <===> " ^ CicPp.ppterm t2);*)
1095 (*
1096 prerr_endline ("PREWHD: " ^ CicPp.ppterm t1 ^ " <===> " ^ CicPp.ppterm t2);
1097    let t1' = whd ?delta:(Some true) ?subst:(Some subst) context t1 in
1098    let t2' = whd ?delta:(Some true) ?subst:(Some subst) context t2 in
1099     debug t1' [t2'] "POSTWHD";
1100 *)
1101 let rec convert_machines test_equality_only ugraph =
1102  function
1103     [] -> true,ugraph
1104   | ((k1,env1,ens1,h1,s1),(k2,env2,ens2,h2,s2))::tl ->
1105      let (b,ugraph) as res =
1106       aux2 test_equality_only
1107        (R.unwind (k1,env1,ens1,h1,[])) (R.unwind (k2,env2,ens2,h2,[])) ugraph
1108      in
1109       if b then
1110        let problems =
1111         try
1112          Some
1113           (List.combine
1114             (List.map
1115               (fun si-> R.reduce ~delta:false ~subst context(RS.from_stack si))
1116               s1)
1117             (List.map
1118               (fun si-> R.reduce ~delta:false ~subst context(RS.from_stack si))
1119               s2)
1120           @ tl)
1121         with
1122          Invalid_argument _ -> None
1123        in
1124         match problems with
1125            None -> false,ugraph
1126          | Some problems -> convert_machines true ugraph problems
1127       else
1128        res
1129 in
1130  convert_machines test_equality_only ugraph
1131   [R.reduce ~delta:true ~subst context (0,[],[],t1,[]),
1132    R.reduce ~delta:true ~subst context (0,[],[],t2,[])]
1133 (*prerr_endline ("POSTWH: " ^ CicPp.ppterm t1' ^ " <===> " ^ CicPp.ppterm t2');*)
1134 (*
1135     aux2 test_equality_only t1' t2' ugraph
1136 *)
1137 end
1138  (*D*)in outside true; rc with exc -> outside false; raise exc
1139  in
1140   aux false (*c t1 t2 ugraph *)
1141 ;;
1142
1143 (* DEBUGGING ONLY
1144 let whd ?(delta=true) ?(subst=[]) context t = 
1145  let res = whd ~delta ~subst context t in
1146  let rescsc = CicReductionNaif.whd ~delta ~subst context t in
1147   if not (fst (are_convertible CicReductionNaif.whd ~subst context res rescsc CicUniv.empty_ugraph)) then
1148    begin
1149     debug_print (lazy ("PRIMA: " ^ CicPp.ppterm t)) ;
1150     flush stderr ;
1151     debug_print (lazy ("DOPO: " ^ CicPp.ppterm res)) ;
1152     flush stderr ;
1153     debug_print (lazy ("CSC: " ^ CicPp.ppterm rescsc)) ;
1154     flush stderr ;
1155 fdebug := 0 ;
1156 let _ =  are_convertible CicReductionNaif.whd ~subst context res rescsc CicUniv.empty_ugraph in
1157     assert false ;
1158    end
1159   else 
1160    res
1161 ;;
1162 *)
1163
1164 let are_convertible = are_convertible whd
1165
1166 let whd = R.whd
1167
1168 (*
1169 let profiler_other_whd = HExtlib.profile ~enable:profile "~are_convertible.whd"
1170 let whd ?(delta=true) ?(subst=[]) context t = 
1171  let foo () =
1172   whd ~delta ~subst context t
1173  in
1174   profiler_other_whd.HExtlib.profile foo ()
1175 *)
1176
1177 let rec normalize ?(delta=true) ?(subst=[]) ctx term =
1178   let module C = Cic in
1179   let t = whd ~delta ~subst ctx term in
1180   let aux = normalize ~delta ~subst in
1181   let decl name t = Some (name, C.Decl t) in
1182   match t with
1183   | C.Rel n -> t
1184   | C.Var (uri,exp_named_subst) ->
1185       C.Var (uri, List.map (fun (n,t) -> n,aux ctx t) exp_named_subst)
1186   | C.Meta (i,l) -> 
1187       C.Meta (i,List.map (function Some t -> Some (aux ctx t) | None -> None) l)
1188   | C.Sort _ -> t
1189   | C.Implicit _ -> t
1190   | C.Cast (te,ty) -> C.Cast (aux ctx te, aux ctx ty)
1191   | C.Prod (n,s,t) -> 
1192       let s' = aux ctx s in
1193       C.Prod (n, s', aux ((decl n s')::ctx) t)
1194   | C.Lambda (n,s,t) -> 
1195       let s' = aux ctx s in
1196       C.Lambda (n, s', aux ((decl n s')::ctx) t)
1197   | C.LetIn (n,s,_,t) ->
1198       (* the term is already in weak head normal form *)
1199       assert false
1200   | C.Appl (h::l) -> C.Appl (h::(List.map (aux ctx) l))
1201   | C.Appl [] -> assert false
1202   | C.Const (uri,exp_named_subst) ->
1203       C.Const (uri, List.map (fun (n,t) -> n,aux ctx t) exp_named_subst)
1204   | C.MutInd (uri,typeno,exp_named_subst) ->
1205       C.MutInd (uri,typeno, List.map (fun (n,t) -> n,aux ctx t) exp_named_subst)
1206   | C.MutConstruct (uri,typeno,consno,exp_named_subst) ->
1207       C.MutConstruct (uri, typeno, consno, 
1208         List.map (fun (n,t) -> n,aux ctx t) exp_named_subst)
1209   | C.MutCase (sp,i,outt,t,pl) ->
1210       C.MutCase (sp,i, aux ctx outt, aux ctx t, List.map (aux ctx) pl)
1211 (*CSC: to be completed, I suppose *)
1212   | C.Fix _ -> t 
1213   | C.CoFix _ -> t
1214
1215 let normalize ?delta ?subst ctx term =  
1216 (*  prerr_endline ("NORMALIZE:" ^ CicPp.ppterm term); *)
1217   let t = normalize ?delta ?subst ctx term in
1218 (*  prerr_endline ("NORMALIZED:" ^ CicPp.ppterm t); *)
1219   t
1220   
1221   
1222 (* performs an head beta/cast reduction *)
1223 let rec head_beta_reduce ?(delta=false) ?(upto=(-1)) t =
1224  match upto with
1225     0 -> t
1226   | n ->
1227     match t with
1228        (Cic.Appl (Cic.Lambda (_,_,t)::he'::tl')) ->
1229          let he'' = CicSubstitution.subst he' t in
1230           if tl' = [] then
1231            he''
1232           else
1233            let he''' =
1234             match he'' with
1235                Cic.Appl l -> Cic.Appl (l@tl')
1236              | _ -> Cic.Appl (he''::tl')
1237            in
1238             head_beta_reduce ~delta ~upto:(upto - 1) he'''
1239      | Cic.Cast (te,_) -> head_beta_reduce ~delta ~upto te
1240      | Cic.Appl (Cic.Const (uri,ens)::tl) as t when delta=true ->
1241         let bo =
1242          match fst (CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri) with
1243             Cic.Constant (_,bo,_,_,_) -> bo
1244           | Cic.Variable _ -> raise ReferenceToVariable
1245           | Cic.CurrentProof (_,_,bo,_,_,_) -> Some bo
1246           | Cic.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
1247         in
1248          (match bo with
1249              None -> t
1250            | Some bo ->
1251               head_beta_reduce ~upto
1252                ~delta (Cic.Appl ((CicSubstitution.subst_vars ens bo)::tl)))
1253      | Cic.Const (uri,ens) as t when delta=true ->
1254         let bo =
1255          match fst (CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri) with
1256             Cic.Constant (_,bo,_,_,_) -> bo
1257           | Cic.Variable _ -> raise ReferenceToVariable
1258           | Cic.CurrentProof (_,_,bo,_,_,_) -> Some bo
1259           | Cic.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
1260         in
1261          (match bo with
1262              None -> t
1263            | Some bo ->
1264               head_beta_reduce ~delta ~upto (CicSubstitution.subst_vars ens bo))
1265      | t -> t
1266
1267 (*
1268 let are_convertible ?subst ?metasenv context t1 t2 ugraph =
1269  let before = Unix.gettimeofday () in
1270  let res = are_convertible ?subst ?metasenv context t1 t2 ugraph in
1271  let after = Unix.gettimeofday () in
1272  let diff = after -. before in
1273   if diff > 0.1 then
1274    begin
1275     let nc = List.map (function None -> None | Some (n,_) -> Some n) context in
1276      prerr_endline
1277       ("\n#(" ^ string_of_float diff ^ "):\n" ^ CicPp.pp t1 nc ^ "\n<=>\n" ^ CicPp.pp t2 nc);
1278    end;
1279   res
1280 *)