1 (* Copyright (C) 2000, HELM Team.
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.
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.
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.
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,
22 * For details, see the HELM World-Wide-Web page,
23 * http://cs.unibo.it/helm/.
28 (* TODO unify exceptions *)
30 exception WrongUriToInductiveDefinition;;
31 exception Impossible of int;;
32 exception ReferenceToConstant;;
33 exception ReferenceToVariable;;
34 exception ReferenceToCurrentProof;;
35 exception ReferenceToInductiveDefinition;;
39 let debug_print s = if debug then prerr_endline (Lazy.force s)
43 let rec debug_aux t i =
45 let module U = UriManager in
46 CicPp.ppobj (C.Variable ("DEBUG", None, t, [], [])) ^ "\n" ^ i
49 debug_print (lazy (s ^ "\n" ^ List.fold_right debug_aux (t::env) ""))
52 module type Strategy =
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) ->
68 val from_ens : ens_term -> config
69 val from_ens_for_unwind :
70 unwind: (config -> Cic.term) ->
73 reduce: (config -> config) ->
74 unwind: (config -> Cic.term) ->
75 stack_term -> env_term
77 reduce: (config -> config) ->
78 unwind: (config -> Cic.term) ->
79 int -> env_term list -> ens_term Cic.explicit_named_substitution ->
81 val compute_to_stack :
82 reduce: (config -> config) ->
83 unwind: (config -> Cic.term) ->
88 module CallByValueByNameForUnwind =
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 *)
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
111 module CallByNameStrategy =
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
119 let from_stack ~unwind v = v
120 let from_stack_list ~unwind l = l
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
132 module CallByNameStrategy =
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
141 let from_stack config = config
142 let from_stack_list_for_unwind ~unwind l = List.map unwind l
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
153 module CallByValueStrategy =
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
161 let from_stack ~unwind v = v
162 let from_stack_list ~unwind l = l
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,[])
173 module CallByValueStrategyByNameOnConstants =
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
181 let from_stack ~unwind v = v
182 let from_stack_list ~unwind l = l
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 =
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 =
194 Cic.Const _ as t -> unwind k e ens t
195 | t -> reduce (k,e,ens,t,[])
199 module LazyCallByValueStrategy =
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,[]))
219 module LazyCallByValueStrategyByNameOnConstants =
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 =
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 =
242 Cic.Const _ as t -> unwind k e ens t
243 | t -> reduce (k,e,ens,t,[]))
247 module LazyCallByNameStrategy =
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)
268 LazyCallByValueByNameOnConstantsWhenFromStack_ByNameStrategyWhenFromEnvOrEns
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
276 let value = lazy v in
277 fun ~reduce -> Lazy.force value
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 =
292 Cic.Const _ as t -> unwind k e ens t
293 | t -> reduce (k,e,ens,t,[])
296 lazy (unwind k e ens t)
299 if reduce then Lazy.force svalue else Lazy.force lvalue
300 let compute_to_env ~reduce ~unwind k e ens t =
304 Cic.Const _ as t -> unwind k e ens t
305 | t -> reduce (k,e,ens,t,[])
308 lazy (unwind k e ens t)
311 if reduce then Lazy.force svalue else Lazy.force lvalue
315 module ClosuresOnStackByValueFromEnvOrEnsStrategy =
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
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
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
336 module ClosuresOnStackByValueFromEnvOrEnsByNameOnConstantsStrategy =
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
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
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) =
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 =
357 let compute_to_stack ~reduce ~unwind k e ens t = (k,e,ens,t)
361 module Reduction(RS : Strategy) =
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
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
376 let rec unwind_aux m =
379 if n <= m then t else
382 Some (RS.from_env_for_unwind ~unwind (List.nth e (n-m-1)))
383 with Failure _ -> None
387 if m = 0 then t' else S.lift m t'
388 | None -> C.Rel (n-k)
390 | C.Var (uri,exp_named_subst) ->
392 debug_print (lazy ("%%%%%UWVAR " ^ String.concat " ; " (List.map (function (uri,t) -> UriManager.string_of_uri uri ^ " := " ^ CicPp.ppterm t) ens))) ;
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))
399 CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
402 C.Constant _ -> raise ReferenceToConstant
403 | C.Variable (_,_,_,params,_) -> params
404 | C.CurrentProof _ -> raise ReferenceToCurrentProof
405 | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
408 let exp_named_subst' =
409 substaux_in_exp_named_subst params exp_named_subst m
411 C.Var (uri,exp_named_subst')
417 | Some t -> Some (unwind_aux m 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) ->
431 CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
434 C.Constant (_,_,_,params,_) -> params
435 | C.Variable _ -> raise ReferenceToVariable
436 | C.CurrentProof (_,_,_,_,params,_) -> params
437 | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
440 let exp_named_subst' =
441 substaux_in_exp_named_subst params exp_named_subst m
443 C.Const (uri,exp_named_subst')
444 | C.MutInd (uri,i,exp_named_subst) ->
447 CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
450 C.Constant _ -> raise ReferenceToConstant
451 | C.Variable _ -> raise ReferenceToVariable
452 | C.CurrentProof _ -> raise ReferenceToCurrentProof
453 | C.InductiveDefinition (_,params,_,_) -> params
456 let exp_named_subst' =
457 substaux_in_exp_named_subst params exp_named_subst m
459 C.MutInd (uri,i,exp_named_subst')
460 | C.MutConstruct (uri,i,j,exp_named_subst) ->
463 CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
466 C.Constant _ -> raise ReferenceToConstant
467 | C.Variable _ -> raise ReferenceToVariable
468 | C.CurrentProof _ -> raise ReferenceToCurrentProof
469 | C.InductiveDefinition (_,params,_,_) -> params
472 let exp_named_subst' =
473 substaux_in_exp_named_subst params exp_named_subst m
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)
480 let len = List.length fl in
483 (fun (name,i,ty,bo) ->
484 (name, i, unwind_aux m ty, unwind_aux (m+len) bo))
487 C.Fix (i, substitutedfl)
489 let len = List.length fl in
492 (fun (name,ty,bo) -> (name, unwind_aux m ty, unwind_aux (m+len) bo))
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
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
503 let rec filter_and_lift =
507 let r = filter_and_lift tl in
509 (uri,(List.assq uri ens'))::r
514 filter_and_lift params
517 (*CSC: invece di concatenare sarebbe meglio rispettare l'ordine dei params *)
518 (*CSC: e' vero???? una veloce prova non sembra confermare la teoria *)
520 (*CSC: codice copiato e modificato dalla cicSubstitution.subst_vars *)
521 (*CSC: codice altamente inefficiente *)
522 let rec filter_and_lift already_instantiated =
527 (function (uri',_)-> not (UriManager.eq uri uri')) exp_named_subst'
529 not (List.mem uri already_instantiated)
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
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") ;
546 List.map (function (uri,t) -> uri, unwind_aux m t) exp_named_subst' @
547 (filter_and_lift [] (List.rev ens))
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))
558 let profiler_unwind = HExtlib.profile ~enable:profile "are_convertible.unwind" in
560 profiler_unwind.HExtlib.profile (unwind k e ens) t
564 let reduce ~delta ?(subst = []) context : config -> config =
565 let module C = Cic in
566 let module S = CicSubstitution in
569 (k, e, _, C.Rel n, s) as config ->
572 Some (RS.from_env (List.nth e (n-1)))
577 match List.nth context (n - 1 - k) with
579 | Some (_,C.Decl _) -> None
580 | Some (_,C.Def (x,_)) -> Some (0,[],[],S.lift (n - k) x,[])
586 Some (k',e',ens',t',s') -> reduce (k',e',ens',t',s'@s)
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)
594 CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
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)
605 | (k, e, ens, C.Meta (n,l), s) as config ->
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) ->
625 (function t -> RS.compute_to_stack ~reduce ~unwind (k,e,ens,t,[])) tl
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 ->
631 CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri
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
646 | (_, _, _, C.MutInd _, _)
647 | (_, _, _, C.MutConstruct _, _) as config -> config
648 | (k, e, ens, C.MutCase (mutind,i,outty,term,pl),s) as config ->
651 (k, e, ens, C.CoFix (i,fl), s) ->
652 let (_,_,body) = List.nth fl i in
654 let counter = ref (List.length fl) in
656 (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
660 reduce (k,e,ens,body',s)
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') ->
669 CicEnvironment.get_cooked_obj CicUniv.empty_ugraph mutind
672 C.InductiveDefinition (_,_,r,_) -> r
673 | _ -> raise WrongUriToInductiveDefinition
676 let num_to_eat = r in
680 | (n,he::s) when n > 0 -> eat_first (n - 1, s)
681 | _ -> raise (Impossible 5)
683 eat_first (num_to_eat,s')
685 reduce (k, e, ens, (List.nth pl (j-1)), ts@s)
686 | (_, _, _, C.Cast _, _)
687 | (_, _, _, C.Implicit _, _) ->
688 raise (Impossible 2) (* we don't trust our whd ;-) *)
690 (*CSC: here I am unwinding the configuration and for sure I
691 will do it twice; to avoid this unwinding I should push the
692 "match [] with _" continuation on the stack;
693 another possibility is to just return the original configuration,
694 partially undoing the weak-head computation *)
695 (*this code is uncorrect since term' lives in e' <> e
696 let term' = unwind config' in
697 (k, e, ens, C.MutCase (mutind,i,outty,term',pl),s)
700 | (k, e, ens, C.Fix (i,fl), s) as config ->
701 let (_,recindex,_,body) = List.nth fl i in
704 Some (RS.from_stack (List.nth s recindex))
710 (match reduce recparam with
711 (_,_,_,C.MutConstruct _,_) as config ->
712 let leng = List.length fl in
714 let counter = ref 0 in
715 let rec build_env e =
716 if !counter = leng then e
720 ((RS.to_env (k,e,ens,C.Fix (!counter -1, fl),[]))::e))
724 let rec replace i s t =
727 | n,he::tl -> he::(replace (n - 1) tl t)
728 | _,_ -> assert false in
730 replace recindex s (RS.compute_to_stack ~reduce ~unwind config)
732 reduce (k+leng, new_env, ens, body, new_s)
736 | (_,_,_,C.CoFix _,_) as config -> config
737 and push_exp_named_subst k e ens =
741 push_exp_named_subst k e ((uri,RS.to_ens (k,e,ens,t,[]))::ens) tl
746 let whd ?(delta=true) ?(subst=[]) context t =
747 unwind (reduce ~delta ~subst context (0, [], [], t, []))
754 (* ROTTO = rompe l'unificazione poiche' riduce gli argomenti di un'applicazione
755 senza ridurre la testa
756 module R = Reduction CallByNameStrategy;; OK 56.368s
757 module R = Reduction CallByValueStrategy;; ROTTO
758 module R = Reduction CallByValueStrategyByNameOnConstants;; ROTTO
759 module R = Reduction LazyCallByValueStrategy;; ROTTO
760 module R = Reduction LazyCallByValueStrategyByNameOnConstants;; ROTTO
761 module R = Reduction LazyCallByNameStrategy;; OK 0m56.398s
763 LazyCallByValueByNameOnConstantsWhenFromStack_ByNameStrategyWhenFromEnvOrEns;;
765 module R = Reduction ClosuresOnStackByValueFromEnvOrEnsStrategy;; OK 58.583s
767 ClosuresOnStackByValueFromEnvOrEnsByNameOnConstantsStrategy;; OK 58.094s
768 module R = Reduction(ClosuresOnStackByValueFromEnvOrEnsStrategy);; OK 58.127s
770 module R = Reduction(CallByValueByNameForUnwind);;
771 (*module R = Reduction(CallByNameStrategy);;*)
772 (*module R = Reduction(ClosuresOnStackByValueFromEnvOrEnsStrategy);;*)
773 module U = UriManager;;
779 let profiler_whd = HExtlib.profile ~enable:profile "are_convertible.whd" in
780 fun ?(delta=true) ?(subst=[]) context t ->
781 profiler_whd.HExtlib.profile (whd ~delta ~subst context) t
784 (* mimic ocaml (<< 3.08) "=" behaviour. Tests physical equality first then
785 * fallbacks to structural equality *)
787 Pervasives.compare x y = 0
789 (* t1, t2 must be well-typed *)
790 let are_convertible whd ?(subst=[]) ?(metasenv=[]) =
791 let heuristic = ref true in
792 let rec aux test_equality_only context t1 t2 ugraph =
793 let rec aux2 test_equality_only t1 t2 ugraph =
795 (* this trivial euristic cuts down the total time of about five times ;-) *)
796 (* this because most of the time t1 and t2 are "sintactically" the same *)
801 let module C = Cic in
803 (C.Rel n1, C.Rel n2) -> (n1 = n2),ugraph
804 | (C.Var (uri1,exp_named_subst1), C.Var (uri2,exp_named_subst2)) ->
805 if U.eq uri1 uri2 then
808 (fun (uri1,x) (uri2,y) (b,ugraph) ->
809 let b',ugraph' = aux test_equality_only context x y ugraph in
810 (U.eq uri1 uri2 && b' && b),ugraph'
811 ) exp_named_subst1 exp_named_subst2 (true,ugraph)
813 Invalid_argument _ -> false,ugraph
817 | (C.Meta (n1,l1), C.Meta (n2,l2)) ->
820 let l1 = CicUtil.clean_up_local_context subst metasenv n1 l1 in
821 let l2 = CicUtil.clean_up_local_context subst metasenv n2 l2 in
823 (fun (b,ugraph) t1 t2 ->
827 | _,None -> true,ugraph
828 | Some t1',Some t2' ->
829 aux test_equality_only context t1' t2' ugraph
832 ) (true,ugraph) l1 l2
834 if b2 then true,ugraph1 else false,ugraph
837 | C.Meta (n1,l1), _ ->
839 let _,term,_ = CicUtil.lookup_subst n1 subst in
840 let term' = CicSubstitution.subst_meta l1 term in
842 prerr_endline ("%?: " ^ CicPp.ppterm t1 ^ " <==> " ^ CicPp.ppterm t2);
843 prerr_endline ("%%%%%%: " ^ CicPp.ppterm term' ^ " <==> " ^ CicPp.ppterm t2);
845 aux test_equality_only context term' t2 ugraph
846 with CicUtil.Subst_not_found _ -> false,ugraph)
847 | _, C.Meta (n2,l2) ->
849 let _,term,_ = CicUtil.lookup_subst n2 subst in
850 let term' = CicSubstitution.subst_meta l2 term in
852 prerr_endline ("%?: " ^ CicPp.ppterm t1 ^ " <==> " ^ CicPp.ppterm t2);
853 prerr_endline ("%%%%%%: " ^ CicPp.ppterm term' ^ " <==> " ^ CicPp.ppterm t1);
855 aux test_equality_only context t1 term' ugraph
856 with CicUtil.Subst_not_found _ -> false,ugraph)
857 (* TASSI: CONSTRAINTS *)
858 | (C.Sort (C.Type t1), C.Sort (C.Type t2)) when test_equality_only ->
859 true,(CicUniv.add_eq t2 t1 ugraph)
860 (* TASSI: CONSTRAINTS *)
861 | (C.Sort (C.Type t1), C.Sort (C.Type t2)) ->
862 true,(CicUniv.add_ge t2 t1 ugraph)
863 (* TASSI: CONSTRAINTS *)
864 | (C.Sort s1, C.Sort (C.Type _)) -> (not test_equality_only),ugraph
865 (* TASSI: CONSTRAINTS *)
866 | (C.Sort s1, C.Sort s2) -> (s1 = s2),ugraph
867 | (C.Prod (name1,s1,t1), C.Prod(_,s2,t2)) ->
868 let b',ugraph' = aux true context s1 s2 ugraph in
870 aux test_equality_only ((Some (name1, (C.Decl s1)))::context)
874 | (C.Lambda (name1,s1,t1), C.Lambda(_,s2,t2)) ->
875 let b',ugraph' = aux test_equality_only context s1 s2 ugraph in
877 aux test_equality_only ((Some (name1, (C.Decl s1)))::context)
881 | (C.LetIn (name1,s1,t1), C.LetIn(_,s2,t2)) ->
882 let b',ugraph' = aux test_equality_only context s1 s2 ugraph in
884 aux test_equality_only
885 ((Some (name1, (C.Def (s1,None))))::context) t1 t2 ugraph'
888 | (C.Appl l1, C.Appl l2) ->
891 (fun x y (b,ugraph) ->
893 aux test_equality_only context x y ugraph
895 false,ugraph) l1 l2 (true,ugraph)
897 Invalid_argument _ -> false,ugraph
899 | (C.Const (uri1,exp_named_subst1), C.Const (uri2,exp_named_subst2)) ->
900 let b' = U.eq uri1 uri2 in
904 (fun (uri1,x) (uri2,y) (b,ugraph) ->
905 if b && U.eq uri1 uri2 then
906 aux test_equality_only context x y ugraph
909 ) exp_named_subst1 exp_named_subst2 (true,ugraph)
911 Invalid_argument _ -> false,ugraph
915 | (C.MutInd (uri1,i1,exp_named_subst1),
916 C.MutInd (uri2,i2,exp_named_subst2)
918 let b' = U.eq uri1 uri2 && i1 = i2 in
922 (fun (uri1,x) (uri2,y) (b,ugraph) ->
923 if b && U.eq uri1 uri2 then
924 aux test_equality_only context x y ugraph
927 ) exp_named_subst1 exp_named_subst2 (true,ugraph)
929 Invalid_argument _ -> false,ugraph
933 | (C.MutConstruct (uri1,i1,j1,exp_named_subst1),
934 C.MutConstruct (uri2,i2,j2,exp_named_subst2)
936 let b' = U.eq uri1 uri2 && i1 = i2 && j1 = j2 in
940 (fun (uri1,x) (uri2,y) (b,ugraph) ->
941 if b && U.eq uri1 uri2 then
942 aux test_equality_only context x y ugraph
945 ) exp_named_subst1 exp_named_subst2 (true,ugraph)
947 Invalid_argument _ -> false,ugraph
951 | (C.MutCase (uri1,i1,outtype1,term1,pl1),
952 C.MutCase (uri2,i2,outtype2,term2,pl2)) ->
953 let b' = U.eq uri1 uri2 && i1 = i2 in
955 let b'',ugraph''=aux test_equality_only context
956 outtype1 outtype2 ugraph in
958 let b''',ugraph'''= aux test_equality_only context
959 term1 term2 ugraph'' in
961 (fun x y (b,ugraph) ->
963 aux test_equality_only context x y ugraph
966 pl1 pl2 (b''',ugraph''')
971 | (C.Fix (i1,fl1), C.Fix (i2,fl2)) ->
973 List.map (function (n,_,ty,_) -> Some (C.Name n,(C.Decl ty))) fl1
977 (fun (_,recindex1,ty1,bo1) (_,recindex2,ty2,bo2) (b,ugraph) ->
978 if b && recindex1 = recindex2 then
979 let b',ugraph' = aux test_equality_only context ty1 ty2
982 aux test_equality_only (tys@context) bo1 bo2 ugraph'
987 fl1 fl2 (true,ugraph)
990 | (C.CoFix (i1,fl1), C.CoFix (i2,fl2)) ->
992 List.map (function (n,ty,_) -> Some (C.Name n,(C.Decl ty))) fl1
996 (fun (_,ty1,bo1) (_,ty2,bo2) (b,ugraph) ->
998 let b',ugraph' = aux test_equality_only context ty1 ty2
1001 aux test_equality_only (tys@context) bo1 bo2 ugraph'
1006 fl1 fl2 (true,ugraph)
1009 | C.Cast (bo,_),t -> aux2 test_equality_only bo t ugraph
1010 | t,C.Cast (bo,_) -> aux2 test_equality_only t bo ugraph
1011 | (C.Implicit _, _) | (_, C.Implicit _) -> assert false
1012 | (_,_) -> false,ugraph
1017 aux2 test_equality_only t1 t2 ugraph
1021 if fst res = true then
1025 (*if !heuristic then prerr_endline ("NON FACILE: " ^ CicPp.ppterm t1 ^ " <===> " ^ CicPp.ppterm t2);*)
1026 (* heuristic := false; *)
1027 debug t1 [t2] "PREWHD";
1028 (*prerr_endline ("PREWHD: " ^ CicPp.ppterm t1 ^ " <===> " ^ CicPp.ppterm t2);*)
1029 let t1' = whd ?delta:(Some true) ?subst:(Some subst) context t1 in
1030 let t2' = whd ?delta:(Some true) ?subst:(Some subst) context t2 in
1031 debug t1' [t2'] "POSTWHD";
1032 (*prerr_endline ("POSTWH: " ^ CicPp.ppterm t1' ^ " <===> " ^ CicPp.ppterm t2');*)
1033 aux2 test_equality_only t1' t2' ugraph
1036 aux false (*c t1 t2 ugraph *)
1040 let whd ?(delta=true) ?(subst=[]) context t =
1041 let res = whd ~delta ~subst context t in
1042 let rescsc = CicReductionNaif.whd ~delta ~subst context t in
1043 if not (fst (are_convertible CicReductionNaif.whd ~subst context res rescsc CicUniv.empty_ugraph)) then
1045 debug_print (lazy ("PRIMA: " ^ CicPp.ppterm t)) ;
1047 debug_print (lazy ("DOPO: " ^ CicPp.ppterm res)) ;
1049 debug_print (lazy ("CSC: " ^ CicPp.ppterm rescsc)) ;
1052 let _ = are_convertible CicReductionNaif.whd ~subst context res rescsc CicUniv.empty_ugraph in
1060 let are_convertible = are_convertible whd
1065 let profiler_other_whd = HExtlib.profile ~enable:profile "~are_convertible.whd"
1066 let whd ?(delta=true) ?(subst=[]) context t =
1068 whd ~delta ~subst context t
1070 profiler_other_whd.HExtlib.profile foo ()
1073 let rec normalize ?(delta=true) ?(subst=[]) ctx term =
1074 let module C = Cic in
1075 let t = whd ~delta ~subst ctx term in
1076 let aux = normalize ~delta ~subst in
1077 let decl name t = Some (name, C.Decl t) in
1080 | C.Var (uri,exp_named_subst) ->
1081 C.Var (uri, List.map (fun (n,t) -> n,aux ctx t) exp_named_subst)
1083 C.Meta (i,List.map (function Some t -> Some (aux ctx t) | None -> None) l)
1086 | C.Cast (te,ty) -> C.Cast (aux ctx te, aux ctx ty)
1088 let s' = aux ctx s in
1089 C.Prod (n, s', aux ((decl n s')::ctx) t)
1090 | C.Lambda (n,s,t) ->
1091 let s' = aux ctx s in
1092 C.Lambda (n, s', aux ((decl n s')::ctx) t)
1093 | C.LetIn (n,s,t) ->
1094 (* the term is already in weak head normal form *)
1096 | C.Appl (h::l) -> C.Appl (h::(List.map (aux ctx) l))
1097 | C.Appl [] -> assert false
1098 | C.Const (uri,exp_named_subst) ->
1099 C.Const (uri, List.map (fun (n,t) -> n,aux ctx t) exp_named_subst)
1100 | C.MutInd (uri,typeno,exp_named_subst) ->
1101 C.MutInd (uri,typeno, List.map (fun (n,t) -> n,aux ctx t) exp_named_subst)
1102 | C.MutConstruct (uri,typeno,consno,exp_named_subst) ->
1103 C.MutConstruct (uri, typeno, consno,
1104 List.map (fun (n,t) -> n,aux ctx t) exp_named_subst)
1105 | C.MutCase (sp,i,outt,t,pl) ->
1106 C.MutCase (sp,i, aux ctx outt, aux ctx t, List.map (aux ctx) pl)
1107 (*CSC: to be completed, I suppose *)
1111 let normalize ?delta ?subst ctx term =
1112 (* prerr_endline ("NORMALIZE:" ^ CicPp.ppterm term); *)
1113 let t = normalize ?delta ?subst ctx term in
1114 (* prerr_endline ("NORMALIZED:" ^ CicPp.ppterm t); *)
1118 (* performs an head beta/cast reduction *)
1119 let rec head_beta_reduce ?(delta=false) =
1121 (Cic.Appl (Cic.Lambda (_,_,t)::he'::tl')) ->
1122 let he'' = CicSubstitution.subst he' t in
1128 Cic.Appl l -> Cic.Appl (l@tl')
1129 | _ -> Cic.Appl (he''::tl')
1131 head_beta_reduce ~delta he'''
1132 | Cic.Cast (te,_) -> head_beta_reduce ~delta te
1133 | Cic.Appl (Cic.Const (uri,ens)::tl) as t when delta=true ->
1135 match fst (CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri) with
1136 Cic.Constant (_,bo,_,_,_) -> bo
1137 | Cic.Variable _ -> raise ReferenceToVariable
1138 | Cic.CurrentProof (_,_,bo,_,_,_) -> Some bo
1139 | Cic.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
1145 ~delta (Cic.Appl ((CicSubstitution.subst_vars ens bo)::tl)))
1146 | Cic.Const (uri,ens) as t when delta=true ->
1148 match fst (CicEnvironment.get_cooked_obj CicUniv.empty_ugraph uri) with
1149 Cic.Constant (_,bo,_,_,_) -> bo
1150 | Cic.Variable _ -> raise ReferenceToVariable
1151 | Cic.CurrentProof (_,_,bo,_,_,_) -> Some bo
1152 | Cic.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
1157 head_beta_reduce ~delta (CicSubstitution.subst_vars ens bo))
1161 let are_convertible ?subst ?metasenv context t1 t2 ugraph =
1162 let before = Unix.gettimeofday () in
1163 let res = are_convertible ?subst ?metasenv context t1 t2 ugraph in
1164 let after = Unix.gettimeofday () in
1165 let diff = after -. before in
1168 let nc = List.map (function None -> None | Some (n,_) -> Some n) context in
1170 ("\n#(" ^ string_of_float diff ^ "):\n" ^ CicPp.pp t1 nc ^ "\n<=>\n" ^ CicPp.pp t2 nc);