]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/ng_kernel/nCicReduction.ml
some bits of reduction, reusing psubst
[helm.git] / helm / software / components / ng_kernel / nCicReduction.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 config = int * env_term list * NCic.term * stack_term list
57   val to_env :
58    reduce: (config -> config) ->
59    unwind: (config -> NCic.term) ->
60    config -> env_term
61   val from_stack : stack_term -> config
62   val from_stack_list_for_unwind :
63    unwind: (config -> NCic.term) ->
64    stack_term list -> NCic.term list
65   val from_env : env_term -> config
66   val from_env_for_unwind :
67    unwind: (config -> NCic.term) ->
68    env_term -> NCic.term
69   val stack_to_env :
70    reduce: (config -> config) ->
71    unwind: (config -> NCic.term) ->
72    stack_term -> env_term
73   val compute_to_env :
74    reduce: (config -> config) ->
75    unwind: (config -> NCic.term) ->
76    int -> env_term list -> 
77     NCic.term -> env_term
78   val compute_to_stack :
79    reduce: (config -> config) ->
80    unwind: (config -> NCic.term) ->
81    config -> stack_term
82  end
83 ;;
84
85 (*
86 module CallByValueByNameForUnwind =
87  struct
88   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
89   and stack_term = config
90   and env_term = config * config (* cbv, cbn *)
91   and ens_term = config * config (* cbv, cbn *)
92
93   let to_env c = c,c
94   let to_ens c = c,c
95   let from_stack config = config
96   let from_stack_list_for_unwind ~unwind l = List.map unwind l
97   let from_env (c,_) = c
98   let from_ens (c,_) = c
99   let from_env_for_unwind ~unwind (_,c) = unwind c
100   let from_ens_for_unwind ~unwind (_,c) = unwind c
101   let stack_to_env ~reduce ~unwind config = reduce config, (0,[],[],unwind config,[])
102   let compute_to_env ~reduce ~unwind k e ens t = (k,e,ens,t,[]), (k,e,ens,t,[])
103   let compute_to_stack ~reduce ~unwind config = config
104  end
105 ;;
106 *)
107
108 module CallByValueByNameForUnwind' =
109  struct
110   type config = int * env_term list * NCic.term * stack_term list
111   and stack_term = config lazy_t * NCic.term lazy_t (* cbv, cbn *)
112   and env_term = config lazy_t * NCic.term lazy_t (* cbv, cbn *)
113   let to_env ~reduce ~unwind c = lazy (reduce c),lazy (unwind c)
114   let from_stack (c,_) = Lazy.force c
115   let from_stack_list_for_unwind ~unwind:_ l = 
116    List.map (function (_,c) -> Lazy.force c) l
117   let from_env (c,_) = Lazy.force c
118   let from_env_for_unwind ~unwind:_ (_,c) = Lazy.force c
119   let stack_to_env ~reduce:_ ~unwind:_ config = config
120   let compute_to_env ~reduce ~unwind k e t =
121    lazy (reduce (k,e,t,[])), lazy (unwind (k,e,t,[]))
122   let compute_to_stack ~reduce ~unwind config = 
123    lazy (reduce config), lazy (unwind config)
124  end
125 ;;
126
127
128 (* Old Machine
129 module CallByNameStrategy =
130  struct
131   type stack_term = Cic.term
132   type env_term = Cic.term
133   type ens_term = Cic.term
134   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
135   let to_env v = v
136   let to_ens v = v
137   let from_stack ~unwind v = v
138   let from_stack_list ~unwind l = l
139   let from_env v = v
140   let from_ens v = v
141   let from_env_for_unwind ~unwind v = v
142   let from_ens_for_unwind ~unwind v = v
143   let stack_to_env ~reduce ~unwind v = v
144   let compute_to_stack ~reduce ~unwind k e ens t = unwind k e ens t
145   let compute_to_env ~reduce ~unwind k e ens t = unwind k e ens t
146  end
147 ;;
148
149 module CallByNameStrategy =
150  struct
151   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
152   and stack_term = config
153   and env_term = config
154   and ens_term = config
155
156   let to_env c = c
157   let to_ens c = c
158   let from_stack config = config
159   let from_stack_list_for_unwind ~unwind l = List.map unwind l
160   let from_env c = c
161   let from_ens c = c
162   let from_env_for_unwind ~unwind c = unwind c
163   let from_ens_for_unwind ~unwind c = unwind c
164   let stack_to_env ~reduce ~unwind config = 0,[],[],unwind config,[]
165   let compute_to_env ~reduce ~unwind k e ens t = k,e,ens,t,[]
166   let compute_to_stack ~reduce ~unwind config = config
167  end
168 ;;
169
170 module CallByValueStrategy =
171  struct
172   type stack_term = Cic.term
173   type env_term = Cic.term
174   type ens_term = Cic.term
175   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
176   let to_env v = v
177   let to_ens v = v
178   let from_stack ~unwind v = v
179   let from_stack_list ~unwind l = l
180   let from_env v = v
181   let from_ens v = v
182   let from_env_for_unwind ~unwind v = v
183   let from_ens_for_unwind ~unwind v = v
184   let stack_to_env ~reduce ~unwind v = v
185   let compute_to_stack ~reduce ~unwind k e ens t = reduce (k,e,ens,t,[])
186   let compute_to_env ~reduce ~unwind k e ens t = reduce (k,e,ens,t,[])
187  end
188 ;;
189
190 module CallByValueStrategyByNameOnConstants =
191  struct
192   type stack_term = Cic.term
193   type env_term = Cic.term
194   type ens_term = Cic.term
195   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
196   let to_env v = v
197   let to_ens v = v
198   let from_stack ~unwind v = v
199   let from_stack_list ~unwind l = l
200   let from_env v = v
201   let from_ens v = v
202   let from_env_for_unwind ~unwind v = v
203   let from_ens_for_unwind ~unwind v = v
204   let stack_to_env ~reduce ~unwind v = v
205   let compute_to_stack ~reduce ~unwind k e ens =
206    function
207       Cic.Const _ as t -> unwind k e ens t    
208     | t -> reduce (k,e,ens,t,[])
209   let compute_to_env ~reduce ~unwind k e ens =
210    function
211       Cic.Const _ as t -> unwind k e ens t    
212     | t -> reduce (k,e,ens,t,[])
213  end
214 ;;
215
216 module LazyCallByValueStrategy =
217  struct
218   type stack_term = Cic.term lazy_t
219   type env_term = Cic.term lazy_t
220   type ens_term = Cic.term lazy_t
221   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
222   let to_env v = lazy v
223   let to_ens v = lazy v
224   let from_stack ~unwind v = Lazy.force v
225   let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
226   let from_env v = Lazy.force v
227   let from_ens v = Lazy.force v
228   let from_env_for_unwind ~unwind v = Lazy.force v
229   let from_ens_for_unwind ~unwind v = Lazy.force v
230   let stack_to_env ~reduce ~unwind v = v
231   let compute_to_stack ~reduce ~unwind k e ens t = lazy (reduce (k,e,ens,t,[]))
232   let compute_to_env ~reduce ~unwind k e ens t = lazy (reduce (k,e,ens,t,[]))
233  end
234 ;;
235
236 module LazyCallByValueStrategyByNameOnConstants =
237  struct
238   type stack_term = Cic.term lazy_t
239   type env_term = Cic.term lazy_t
240   type ens_term = Cic.term lazy_t
241   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
242   let to_env v = lazy v
243   let to_ens v = lazy v
244   let from_stack ~unwind v = Lazy.force v
245   let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
246   let from_env v = Lazy.force v
247   let from_ens v = Lazy.force v
248   let from_env_for_unwind ~unwind v = Lazy.force v
249   let from_ens_for_unwind ~unwind v = Lazy.force v
250   let stack_to_env ~reduce ~unwind v = v
251   let compute_to_stack ~reduce ~unwind k e ens t =
252    lazy (
253     match t with
254        Cic.Const _ as t -> unwind k e ens t    
255      | t -> reduce (k,e,ens,t,[]))
256   let compute_to_env ~reduce ~unwind k e ens t =
257    lazy (
258     match t with
259        Cic.Const _ as t -> unwind k e ens t    
260      | t -> reduce (k,e,ens,t,[]))
261  end
262 ;;
263
264 module LazyCallByNameStrategy =
265  struct
266   type stack_term = Cic.term lazy_t
267   type env_term = Cic.term lazy_t
268   type ens_term = Cic.term lazy_t
269   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
270   let to_env v = lazy v
271   let to_ens v = lazy v
272   let from_stack ~unwind v = Lazy.force v
273   let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
274   let from_env v = Lazy.force v
275   let from_ens v = Lazy.force v
276   let from_env_for_unwind ~unwind v = Lazy.force v
277   let from_ens_for_unwind ~unwind v = Lazy.force v
278   let stack_to_env ~reduce ~unwind v = v
279   let compute_to_stack ~reduce ~unwind k e ens t = lazy (unwind k e ens t)
280   let compute_to_env ~reduce ~unwind k e ens t = lazy (unwind k e ens t)
281  end
282 ;;
283
284 module
285  LazyCallByValueByNameOnConstantsWhenFromStack_ByNameStrategyWhenFromEnvOrEns
286 =
287  struct
288   type stack_term = reduce:bool -> Cic.term
289   type env_term = reduce:bool -> Cic.term
290   type ens_term = reduce:bool -> Cic.term
291   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
292   let to_env v =
293    let value = lazy v in
294     fun ~reduce -> Lazy.force value
295   let to_ens v =
296    let value = lazy v in
297     fun ~reduce -> Lazy.force value
298   let from_stack ~unwind v = (v ~reduce:false)
299   let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
300   let from_env v = (v ~reduce:true)
301   let from_ens v = (v ~reduce:true)
302   let from_env_for_unwind ~unwind v = (v ~reduce:true)
303   let from_ens_for_unwind ~unwind v = (v ~reduce:true)
304   let stack_to_env ~reduce ~unwind v = v
305   let compute_to_stack ~reduce ~unwind k e ens t =
306    let svalue =
307      lazy (
308       match t with
309          Cic.Const _ as t -> unwind k e ens t    
310        | t -> reduce (k,e,ens,t,[])
311      ) in
312    let lvalue =
313     lazy (unwind k e ens t)
314    in
315     fun ~reduce ->
316      if reduce then Lazy.force svalue else Lazy.force lvalue
317   let compute_to_env ~reduce ~unwind k e ens t =
318    let svalue =
319      lazy (
320       match t with
321          Cic.Const _ as t -> unwind k e ens t    
322        | t -> reduce (k,e,ens,t,[])
323      ) in
324    let lvalue =
325     lazy (unwind k e ens t)
326    in
327     fun ~reduce ->
328      if reduce then Lazy.force svalue else Lazy.force lvalue
329  end
330 ;;
331
332 module ClosuresOnStackByValueFromEnvOrEnsStrategy =
333  struct
334   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
335   and stack_term = config
336   and env_term = config
337   and ens_term = config
338
339   let to_env config = config
340   let to_ens config = config
341   let from_stack config = config
342   let from_stack_list_for_unwind ~unwind l = List.map unwind l
343   let from_env v = v
344   let from_ens v = v
345   let from_env_for_unwind ~unwind config = unwind config
346   let from_ens_for_unwind ~unwind config = unwind config
347   let stack_to_env ~reduce ~unwind config = reduce config
348   let compute_to_env ~reduce ~unwind k e ens t = (k,e,ens,t,[])
349   let compute_to_stack ~reduce ~unwind config = config
350  end
351 ;;
352
353 module ClosuresOnStackByValueFromEnvOrEnsByNameOnConstantsStrategy =
354  struct
355   type stack_term =
356    int * Cic.term list * Cic.term Cic.explicit_named_substitution * Cic.term
357   type env_term = Cic.term
358   type ens_term = Cic.term
359   type config = int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term * stack_term list
360   let to_env v = v
361   let to_ens v = v
362   let from_stack ~unwind (k,e,ens,t) = unwind k e ens t
363   let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
364   let from_env v = v
365   let from_ens v = v
366   let from_env_for_unwind ~unwind v = v
367   let from_ens_for_unwind ~unwind v = v
368   let stack_to_env ~reduce ~unwind (k,e,ens,t) =
369    match t with
370       Cic.Const _ as t -> unwind k e ens t    
371     | t -> reduce (k,e,ens,t,[])
372   let compute_to_env ~reduce ~unwind k e ens t =
373    unwind k e ens t
374   let compute_to_stack ~reduce ~unwind k e ens t = (k,e,ens,t)
375  end
376 ;;
377
378 *)
379
380 module Reduction(RS : Strategy) =
381  struct
382   type env = RS.env_term list
383   type stack = RS.stack_term list
384   type config = int * env * NCic.term * stack
385
386   let rec unwind (k,e,t,s) =
387     let t = 
388       if k = 0 then t 
389       else 
390         NCicSubstitution.psubst ~avoid_beta_redexes:true  
391           true 0 (RS.from_env_for_unwind ~unwind) e t
392     in
393     if s = [] then t 
394     else NCic.Appl(t::(RS.from_stack_list_for_unwind ~unwind s))
395   ;;
396
397   let list_nth l n = try List.nth l n with Failure _ -> assert false;;
398   let rec replace i s t =
399     match i,s with
400     |  0,_::tl -> t::tl
401     | n,he::tl -> he::(replace (n - 1) tl t)
402     | _,_ -> assert false
403   ;;
404
405   let rec reduce ~delta ?(subst = []) context : config -> config = 
406    let rec aux = function
407      | k, e, NCic.Rel n, s when n <= k ->
408         let k',e',t',s' = RS.from_env (list_nth e (n-1)) in
409         aux (k',e',t',s'@s)
410      | k, _, NCic.Rel n, s as config (* when n > k *) ->
411         (match List.nth context (n - 1 - k) with
412         | (_,NCic.Decl _) -> config
413         | (_,NCic.Def (x,_)) -> aux (0,[],NCicSubstitution.lift (n - k) x,s))
414      | (k, e, NCic.Meta (n,l), s) as config ->
415         (try 
416            let _,_, term,_ = NCicUtils.lookup_subst n subst in
417            aux (k, e, NCicSubstitution.subst_meta l term,s)
418          with  NCicUtils.Subst_not_found _ -> config)
419      | (_, _, NCic.Sort _, _) as config -> config
420      | (_, _, NCic.Implicit _, _) -> assert false
421      | (_, _, NCic.Prod _, _) as config -> config
422      | (_, _, NCic.Lambda _, []) as config -> config
423      | (k, e, NCic.Lambda (_,_,t), p::s) ->
424          aux (k+1, (RS.stack_to_env ~reduce:aux ~unwind p)::e, t,s)
425      | (k, e, NCic.LetIn (_,_,m,t), s) ->
426         let m' = RS.compute_to_env ~reduce:aux ~unwind k e m in
427          aux (k+1, m'::e, t, s)
428      | (_, _, NCic.Appl [], _) -> assert false
429      | (k, e, NCic.Appl (he::tl), s) ->
430         let tl' =
431          List.map (fun t->RS.compute_to_stack ~reduce:aux ~unwind (k,e,t,[])) tl
432         in
433          aux (k, e, he, tl' @ s)
434      | (_, _, NCic.Const(NReference.Ref (_,_,NReference.Def) as refer), s) as config ->
435          let _,_,body,_,_,height = NCicEnvironment.get_checked_def refer in
436          if delta >= height then config else aux (0, [], body, s) 
437      | (_, _, NCic.Const (NReference.Ref 
438                (_,_,NReference.Fix (_,recindex)) as refer),s) as config ->
439         let _,_,body,_, _, height = NCicEnvironment.get_checked_fix refer in
440         if delta >= height then config else
441         (match
442           try Some (RS.from_stack (List.nth s recindex))
443           with Failure _ -> None
444         with 
445         | None -> config
446         | Some recparam ->
447            match reduce ~delta:0 ~subst context recparam with
448            | (_,_,NCic.Const (NReference.Ref (_,_,NReference.Con _)), _) as c ->
449                let new_s =
450                  replace recindex s (RS.compute_to_stack ~reduce:aux ~unwind c)
451                in
452                aux (0, [], body, new_s)
453            | _ -> config)
454      | (_, _, NCic.Const _, _) as config -> config
455      | (k, e, NCic.Match (_,_,term,pl),s) as config ->
456         let decofix = function
457           | (_,_,NCic.Const(NReference.Ref(_,_,NReference.CoFix _)as refer),s)->
458              let _,_,body,_,_,_ = NCicEnvironment.get_checked_cofix refer in
459              reduce ~delta:0 ~subst context (0,[],body,s)
460           | config -> config
461         in
462         (match decofix (reduce ~delta:0 ~subst context (k,e,term,[])) with
463         | (_, _, NCic.Const (NReference.Ref (_,_,NReference.Con (_,j))),[]) ->
464             aux (k, e, List.nth pl (j-1), s)
465         | (_, _, NCic.Const 
466              (NReference.Ref (_,_,NReference.Con (_,j)) as refer), s') ->
467           let leftno = NCicEnvironment.get_indty_leftno refer in
468           let _,params = HExtlib.split_nth leftno s' in
469           aux (k, e, List.nth pl (j-1), params@s)
470         | _ -> config)
471    in
472     aux
473   ;;
474
475   let whd ?(delta=0) ?(subst=[]) context t = 
476    unwind (reduce ~delta ~subst context (0, [], t, []))
477   ;;
478
479  end
480 ;;
481
482
483 (* ROTTO = rompe l'unificazione poiche' riduce gli argomenti di un'applicazione
484            senza ridurre la testa
485 module R = Reduction CallByNameStrategy;; OK 56.368s
486 module R = Reduction CallByValueStrategy;; ROTTO
487 module R = Reduction CallByValueStrategyByNameOnConstants;; ROTTO
488 module R = Reduction LazyCallByValueStrategy;; ROTTO
489 module R = Reduction LazyCallByValueStrategyByNameOnConstants;; ROTTO
490 module R = Reduction LazyCallByNameStrategy;; OK 0m56.398s
491 module R = Reduction
492  LazyCallByValueByNameOnConstantsWhenFromStack_ByNameStrategyWhenFromEnvOrEns;;
493  OK 59.058s
494 module R = Reduction ClosuresOnStackByValueFromEnvOrEnsStrategy;; OK 58.583s
495 module R = Reduction
496  ClosuresOnStackByValueFromEnvOrEnsByNameOnConstantsStrategy;; OK 58.094s
497 module R = Reduction(ClosuresOnStackByValueFromEnvOrEnsStrategy);; OK 58.127s
498 *)
499 (*module R = Reduction(CallByValueByNameForUnwind);;*)
500 module RS = CallByValueByNameForUnwind';;
501 (*module R = Reduction(CallByNameStrategy);;*)
502 (*module R = Reduction(ClosuresOnStackByValueFromEnvOrEnsStrategy);;*)
503
504 (*
505 module R = Reduction(RS);;
506 module U = UriManager;;
507
508 let whd = R.whd
509 *)
510
511 (*
512 let whd =
513  let profiler_whd = HExtlib.profile ~enable:profile "are_convertible.whd" in
514   fun ?(delta=true) ?(subst=[]) context t ->
515    profiler_whd.HExtlib.profile (whd ~delta ~subst context) t
516 *)
517
518 (*
519
520   (* mimic ocaml (<< 3.08) "=" behaviour. Tests physical equality first then
521     * fallbacks to structural equality *)
522 let (===) x y =
523   Pervasives.compare x y = 0
524
525 (* t1, t2 must be well-typed *)
526 let are_convertible whd ?(subst=[]) ?(metasenv=[])  =
527  let heuristic = ref true in
528  let rec aux test_equality_only context t1 t2 ugraph =
529   let rec aux2 test_equality_only t1 t2 ugraph =
530
531    (* this trivial euristic cuts down the total time of about five times ;-) *)
532    (* this because most of the time t1 and t2 are "sintactically" the same   *)
533    if t1 === t2 then
534      true,ugraph
535    else
536     begin
537      let module C = Cic in
538        match (t1,t2) with
539           (C.Rel n1, C.Rel n2) -> (n1 = n2),ugraph
540         | (C.Var (uri1,exp_named_subst1), C.Var (uri2,exp_named_subst2)) ->
541             if U.eq uri1 uri2 then
542              (try
543                List.fold_right2
544                 (fun (uri1,x) (uri2,y) (b,ugraph) ->
545                   let b',ugraph' = aux test_equality_only context x y ugraph in
546                   (U.eq uri1 uri2 && b' && b),ugraph'
547                 ) exp_named_subst1 exp_named_subst2 (true,ugraph) 
548               with
549                Invalid_argument _ -> false,ugraph
550              )
551             else
552               false,ugraph
553         | (C.Meta (n1,l1), C.Meta (n2,l2)) ->
554             if n1 = n2 then
555               let b2, ugraph1 = 
556                 let l1 = CicUtil.clean_up_local_context subst metasenv n1 l1 in
557                 let l2 = CicUtil.clean_up_local_context subst metasenv n2 l2 in
558                   List.fold_left2
559                     (fun (b,ugraph) t1 t2 ->
560                        if b then 
561                          match t1,t2 with
562                              None,_
563                            | _,None  -> true,ugraph
564                            | Some t1',Some t2' -> 
565                                aux test_equality_only context t1' t2' ugraph
566                        else
567                          false,ugraph
568                     ) (true,ugraph) l1 l2
569               in
570                 if b2 then true,ugraph1 else false,ugraph 
571             else
572               false,ugraph
573         | C.Meta (n1,l1), _ ->
574            (try 
575               let _,term,_ = NCicUtils.lookup_subst n1 subst in
576               let term' = CicSubstitution.subst_meta l1 term in
577 (*
578 prerr_endline ("%?: " ^ CicPp.ppterm t1 ^ " <==> " ^ CicPp.ppterm t2);
579 prerr_endline ("%%%%%%: " ^ CicPp.ppterm term' ^ " <==> " ^ CicPp.ppterm t2);
580 *)
581                aux test_equality_only context term' t2 ugraph
582             with  CicUtil.Subst_not_found _ -> false,ugraph)
583         | _, C.Meta (n2,l2) ->
584            (try 
585               let _,term,_ = CicUtil.lookup_subst n2 subst in
586               let term' = CicSubstitution.subst_meta l2 term in
587 (*
588 prerr_endline ("%?: " ^ CicPp.ppterm t1 ^ " <==> " ^ CicPp.ppterm t2);
589 prerr_endline ("%%%%%%: " ^ CicPp.ppterm term' ^ " <==> " ^ CicPp.ppterm t1);
590 *)
591                aux test_equality_only context t1 term' ugraph
592             with  CicUtil.Subst_not_found _ -> false,ugraph)
593           (* TASSI: CONSTRAINTS *)
594         | (C.Sort (C.Type t1), C.Sort (C.Type t2)) when test_equality_only ->
595             (try
596               true,(CicUniv.add_eq t2 t1 ugraph)
597              with CicUniv.UniverseInconsistency _ -> false,ugraph)
598         | (C.Sort (C.Type t1), C.Sort (C.Type t2)) ->
599             (try
600               true,(CicUniv.add_ge t2 t1 ugraph)
601              with CicUniv.UniverseInconsistency _ -> false,ugraph)
602         | (C.Sort s1, C.Sort (C.Type _)) -> (not test_equality_only),ugraph
603         | (C.Sort s1, C.Sort s2) -> (s1 = s2),ugraph
604         | (C.Prod (name1,s1,t1), C.Prod(_,s2,t2)) ->
605             let b',ugraph' = aux true context s1 s2 ugraph in
606             if b' then 
607               aux test_equality_only ((Some (name1, (C.Decl s1)))::context) 
608                 t1 t2 ugraph'
609             else
610               false,ugraph
611         | (C.Lambda (name1,s1,t1), C.Lambda(_,s2,t2)) ->
612            let b',ugraph' = aux test_equality_only context s1 s2 ugraph in
613            if b' then
614              aux test_equality_only ((Some (name1, (C.Decl s1)))::context) 
615                t1 t2 ugraph'
616            else
617              false,ugraph
618         | (C.LetIn (name1,s1,t1), C.LetIn(_,s2,t2)) ->
619            let b',ugraph' = aux test_equality_only context s1 s2 ugraph in
620            if b' then
621             aux test_equality_only
622              ((Some (name1, (C.Def (s1,None))))::context) t1 t2 ugraph'
623            else
624              false,ugraph
625         | (C.Appl l1, C.Appl l2) ->
626            (try
627              List.fold_right2
628                (fun  x y (b,ugraph) -> 
629                  if b then
630                    aux test_equality_only context x y ugraph
631                  else
632                    false,ugraph) l1 l2 (true,ugraph)
633             with
634              Invalid_argument _ -> false,ugraph
635            )
636         | (C.Const (uri1,exp_named_subst1), C.Const (uri2,exp_named_subst2)) ->
637             let b' = U.eq uri1 uri2 in
638             if b' then
639              (try
640                List.fold_right2
641                 (fun (uri1,x) (uri2,y) (b,ugraph) ->
642                   if b && U.eq uri1 uri2 then
643                     aux test_equality_only context x y ugraph 
644                   else
645                     false,ugraph
646                 ) exp_named_subst1 exp_named_subst2 (true,ugraph)
647               with
648                Invalid_argument _ -> false,ugraph
649              )
650             else
651               false,ugraph
652         | (C.MutInd (uri1,i1,exp_named_subst1),
653            C.MutInd (uri2,i2,exp_named_subst2)
654           ) ->
655             let b' = U.eq uri1 uri2 && i1 = i2 in
656             if b' then
657              (try
658                List.fold_right2
659                 (fun (uri1,x) (uri2,y) (b,ugraph) ->
660                   if b && U.eq uri1 uri2 then
661                     aux test_equality_only context x y ugraph
662                   else
663                    false,ugraph
664                 ) exp_named_subst1 exp_named_subst2 (true,ugraph)
665               with
666                Invalid_argument _ -> false,ugraph
667              )
668             else 
669               false,ugraph
670         | (C.MutConstruct (uri1,i1,j1,exp_named_subst1),
671            C.MutConstruct (uri2,i2,j2,exp_named_subst2)
672           ) ->
673             let b' = U.eq uri1 uri2 && i1 = i2 && j1 = j2 in
674             if b' then
675              (try
676                List.fold_right2
677                 (fun (uri1,x) (uri2,y) (b,ugraph) ->
678                   if b && U.eq uri1 uri2 then
679                     aux test_equality_only context x y ugraph
680                   else
681                     false,ugraph
682                 ) exp_named_subst1 exp_named_subst2 (true,ugraph)
683               with
684                Invalid_argument _ -> false,ugraph
685              )
686             else
687               false,ugraph
688         | (C.MutCase (uri1,i1,outtype1,term1,pl1),
689            C.MutCase (uri2,i2,outtype2,term2,pl2)) -> 
690             let b' = U.eq uri1 uri2 && i1 = i2 in
691             if b' then
692              let b'',ugraph''=aux test_equality_only context 
693                  outtype1 outtype2 ugraph in
694              if b'' then 
695                let b''',ugraph'''= aux test_equality_only context 
696                    term1 term2 ugraph'' in
697                List.fold_right2
698                  (fun x y (b,ugraph) -> 
699                    if b then
700                      aux test_equality_only context x y ugraph 
701                    else 
702                      false,ugraph)
703                  pl1 pl2 (b''',ugraph''')
704              else
705                false,ugraph
706             else
707               false,ugraph
708         | (C.Fix (i1,fl1), C.Fix (i2,fl2)) ->
709             let tys,_ =
710               List.fold_left
711                 (fun (types,len) (n,_,ty,_) ->
712                    (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
713                     len+1)
714                 ) ([],0) fl1
715             in
716             if i1 = i2 then
717              List.fold_right2
718               (fun (_,recindex1,ty1,bo1) (_,recindex2,ty2,bo2) (b,ugraph) ->
719                 if b && recindex1 = recindex2 then
720                   let b',ugraph' = aux test_equality_only context ty1 ty2 
721                       ugraph in
722                   if b' then
723                     aux test_equality_only (tys@context) bo1 bo2 ugraph'
724                   else
725                     false,ugraph
726                 else
727                   false,ugraph)
728              fl1 fl2 (true,ugraph)
729             else
730               false,ugraph
731         | (C.CoFix (i1,fl1), C.CoFix (i2,fl2)) ->
732             let tys,_ =
733               List.fold_left
734                 (fun (types,len) (n,ty,_) ->
735                    (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
736                     len+1)
737                 ) ([],0) fl1
738             in
739             if i1 = i2 then
740               List.fold_right2
741               (fun (_,ty1,bo1) (_,ty2,bo2) (b,ugraph) ->
742                 if b then
743                   let b',ugraph' = aux test_equality_only context ty1 ty2 
744                       ugraph in
745                   if b' then
746                     aux test_equality_only (tys@context) bo1 bo2 ugraph'
747                   else
748                     false,ugraph
749                 else
750                   false,ugraph)
751              fl1 fl2 (true,ugraph)
752             else
753               false,ugraph
754         | C.Cast (bo,_),t -> aux2 test_equality_only bo t ugraph
755         | t,C.Cast (bo,_) -> aux2 test_equality_only t bo ugraph
756         | (C.Implicit _, _) | (_, C.Implicit _) -> assert false
757         | (_,_) -> false,ugraph
758     end
759   in
760    let res =
761     if !heuristic then
762      aux2 test_equality_only t1 t2 ugraph
763     else
764      false,ugraph
765    in
766     if fst res = true then
767      res
768     else
769 begin
770 (*if !heuristic then prerr_endline ("NON FACILE: " ^ CicPp.ppterm t1 ^ " <===> " ^ CicPp.ppterm t2);*)
771    (* heuristic := false; *)
772    debug t1 [t2] "PREWHD";
773 (*prerr_endline ("PREWHD: " ^ CicPp.ppterm t1 ^ " <===> " ^ CicPp.ppterm t2);*)
774 (*
775 prerr_endline ("PREWHD: " ^ CicPp.ppterm t1 ^ " <===> " ^ CicPp.ppterm t2);
776    let t1' = whd ?delta:(Some true) ?subst:(Some subst) context t1 in
777    let t2' = whd ?delta:(Some true) ?subst:(Some subst) context t2 in
778     debug t1' [t2'] "POSTWHD";
779 *)
780 let rec convert_machines ugraph =
781  function
782     [] -> true,ugraph
783   | ((k1,env1,ens1,h1,s1),(k2,env2,ens2,h2,s2))::tl ->
784      let (b,ugraph) as res =
785       aux2 test_equality_only
786        (R.unwind (k1,env1,ens1,h1,[])) (R.unwind (k2,env2,ens2,h2,[])) ugraph
787      in
788       if b then
789        let problems =
790         try
791          Some
792           (List.combine
793             (List.map
794               (fun si-> R.reduce ~delta:false ~subst context(RS.from_stack si))
795               s1)
796             (List.map
797               (fun si-> R.reduce ~delta:false ~subst context(RS.from_stack si))
798               s2)
799           @ tl)
800         with
801          Invalid_argument _ -> None
802        in
803         match problems with
804            None -> false,ugraph
805          | Some problems -> convert_machines ugraph problems
806       else
807        res
808 in
809  convert_machines ugraph
810   [R.reduce ~delta:true ~subst context (0,[],[],t1,[]),
811    R.reduce ~delta:true ~subst context (0,[],[],t2,[])]
812 (*prerr_endline ("POSTWH: " ^ CicPp.ppterm t1' ^ " <===> " ^ CicPp.ppterm t2');*)
813 (*
814     aux2 test_equality_only t1' t2' ugraph
815 *)
816 end
817  in
818   aux false (*c t1 t2 ugraph *)
819 ;;
820 *)
821
822 (* DEBUGGING ONLY
823 let whd ?(delta=true) ?(subst=[]) context t = 
824  let res = whd ~delta ~subst context t in
825  let rescsc = CicReductionNaif.whd ~delta ~subst context t in
826   if not (fst (are_convertible CicReductionNaif.whd ~subst context res rescsc CicUniv.empty_ugraph)) then
827    begin
828     debug_print (lazy ("PRIMA: " ^ CicPp.ppterm t)) ;
829     flush stderr ;
830     debug_print (lazy ("DOPO: " ^ CicPp.ppterm res)) ;
831     flush stderr ;
832     debug_print (lazy ("CSC: " ^ CicPp.ppterm rescsc)) ;
833     flush stderr ;
834 fdebug := 0 ;
835 let _ =  are_convertible CicReductionNaif.whd ~subst context res rescsc CicUniv.empty_ugraph in
836     assert false ;
837    end
838   else 
839    res
840 ;;
841 *)
842
843 (*
844 let are_convertible = are_convertible whd
845
846 let whd = R.whd
847 *)
848
849 (*
850 let profiler_other_whd = HExtlib.profile ~enable:profile "~are_convertible.whd"
851 let whd ?(delta=true) ?(subst=[]) context t = 
852  let foo () =
853   whd ~delta ~subst context t
854  in
855   profiler_other_whd.HExtlib.profile foo ()
856 *)
857
858 (*
859 let rec normalize ?(delta=true) ?(subst=[]) ctx term =
860   let module C = Cic in
861   let t = whd ~delta ~subst ctx term in
862   let aux = normalize ~delta ~subst in
863   let decl name t = Some (name, C.Decl t) in
864   match t with
865   | C.Rel n -> t
866   | C.Var (uri,exp_named_subst) ->
867       C.Var (uri, List.map (fun (n,t) -> n,aux ctx t) exp_named_subst)
868   | C.Meta (i,l) -> 
869       C.Meta (i,List.map (function Some t -> Some (aux ctx t) | None -> None) l)
870   | C.Sort _ -> t
871   | C.Implicit _ -> t
872   | C.Cast (te,ty) -> C.Cast (aux ctx te, aux ctx ty)
873   | C.Prod (n,s,t) -> 
874       let s' = aux ctx s in
875       C.Prod (n, s', aux ((decl n s')::ctx) t)
876   | C.Lambda (n,s,t) -> 
877       let s' = aux ctx s in
878       C.Lambda (n, s', aux ((decl n s')::ctx) t)
879   | C.LetIn (n,s,t) ->
880       (* the term is already in weak head normal form *)
881       assert false
882   | C.Appl (h::l) -> C.Appl (h::(List.map (aux ctx) l))
883   | C.Appl [] -> assert false
884   | C.Const (uri,exp_named_subst) ->
885       C.Const (uri, List.map (fun (n,t) -> n,aux ctx t) exp_named_subst)
886   | C.MutInd (uri,typeno,exp_named_subst) ->
887       C.MutInd (uri,typeno, List.map (fun (n,t) -> n,aux ctx t) exp_named_subst)
888   | C.MutConstruct (uri,typeno,consno,exp_named_subst) ->
889       C.MutConstruct (uri, typeno, consno, 
890         List.map (fun (n,t) -> n,aux ctx t) exp_named_subst)
891   | C.MutCase (sp,i,outt,t,pl) ->
892       C.MutCase (sp,i, aux ctx outt, aux ctx t, List.map (aux ctx) pl)
893 (*CSC: to be completed, I suppose *)
894   | C.Fix _ -> t 
895   | C.CoFix _ -> t
896 *)
897
898 (*  
899 let normalize ?delta ?subst ctx term =  
900 (*  prerr_endline ("NORMALIZE:" ^ CicPp.ppterm term); *)
901   let t = normalize ?delta ?subst ctx term in
902 (*  prerr_endline ("NORMALIZED:" ^ CicPp.ppterm t); *)
903   t
904 *)
905   
906 (* performs an head beta/cast reduction 
907 let rec head_beta_reduce ?(delta=false) ?(upto=(-1)) t =
908  match upto with
909     0 -> t
910   | n ->
911     match t with
912        (Cic.Appl (Cic.Lambda (_,_,t)::he'::tl')) ->
913          let he'' = CicSubstitution.subst he' t in
914           if tl' = [] then
915            he''
916           else
917            let he''' =
918             match he'' with
919                Cic.Appl l -> Cic.Appl (l@tl')
920              | _ -> Cic.Appl (he''::tl')
921            in
922             head_beta_reduce ~delta ~upto:(upto - 1) he'''
923      | Cic.Cast (te,_) -> head_beta_reduce ~delta ~upto te
924      | Cic.Appl (Cic.Const (uri,ens)::tl) as t when delta=true ->
925         let bo =
926          match fst (CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri) with
927             Cic.Constant (_,bo,_,_,_) -> bo
928           | Cic.Variable _ -> raise ReferenceToVariable
929           | Cic.CurrentProof (_,_,bo,_,_,_) -> Some bo
930           | Cic.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
931         in
932          (match bo with
933              None -> t
934            | Some bo ->
935               head_beta_reduce ~upto
936                ~delta (Cic.Appl ((CicSubstitution.subst_vars ens bo)::tl)))
937      | Cic.Const (uri,ens) as t when delta=true ->
938         let bo =
939          match fst (CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri) with
940             Cic.Constant (_,bo,_,_,_) -> bo
941           | Cic.Variable _ -> raise ReferenceToVariable
942           | Cic.CurrentProof (_,_,bo,_,_,_) -> Some bo
943           | Cic.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
944         in
945          (match bo with
946              None -> t
947            | Some bo ->
948               head_beta_reduce ~delta ~upto (CicSubstitution.subst_vars ens bo))
949      | t -> t
950 *)
951 (*
952 let are_convertible ?subst ?metasenv context t1 t2 ugraph =
953  let before = Unix.gettimeofday () in
954  let res = are_convertible ?subst ?metasenv context t1 t2 ugraph in
955  let after = Unix.gettimeofday () in
956  let diff = after -. before in
957   if diff > 0.1 then
958    begin
959     let nc = List.map (function None -> None | Some (n,_) -> Some n) context in
960      prerr_endline
961       ("\n#(" ^ string_of_float diff ^ "):\n" ^ CicPp.pp t1 nc ^ "\n<=>\n" ^ CicPp.pp t2 nc);
962    end;
963   res
964 *)