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