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